Skip to content

Jetty WebSocket (часть 2)

Синопсис

В предыдущем посте мы создали Jetty Server который стартует прямо с main метода. В этом посте добавим к jetty серверу веб сокеты.

Готовый проект можно взять с gitHub по ссылке: https://github.com/dev-blogs/JettyWebSocket

Что такое веб сокеты

Когда jetty сервак запущен, в принципе возникнуть вопроса как к нему коннектиться не должно, по умолчанию это http протокол. Но http протокол имеет у http протокола есть известный недостаток в который в этом посте мы вдаваться не будем, скажу лишь, что для того чтобы обеспечить взаимодействия клиента с сервером по средствам протокола http, клиент и сервер каждый раз должны заново инициировать соединение, причем соединение только в одну сторону, если клиент ожидает что-то получить от сервера, то приходится опять устанавливать соединение. Поэтому протокол http еще называют stateless протоколом, это означает, что он не сохраняет своего последнего (и вообще никакого) состояния. Для того, чтобы присутствовала иллюзия того, что такое состояние сохраняется, когда вы взаимодействуйте с каким-нибудь веб ресурсом, на пример с веб почтой, используя протокол http, в этом случае применяются разного рода костыли, на пример токены.
В отличие от http протокола соединение клиента и сервера по средством веб сокетов осуществляется двунаправленно, то есть между клиентом и сервером устанавливается канал, через который они могут общаться в реальном времени.

Структура проекта

Структура проекта такая же как и в предыдущем посте отличие будет в добавлении дополнительных классов, которые отвечают за создание веб сокетов:

JettWebSocket
    ├──src
    │   ├─main
    │   │  └─java
    │   │     └─our
    │   │        └─task
    │   │            ├─JettyServer
    │   │            │   └─JettyStarter.java
    │   │            └─JettyWebSocket
    │   │                ├─MySocket.java
    │   │                └─SocketHandler.java
    │   └─test
    │      └─java
    │         └─our
    │            └─task
    │                ├─JettyServer
    │                └─JettyWebSocket
    └──pom.xml

Java классы

JettyStarter.java

package our.task.JettyServer;

import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler;

import our.task.JettyWebSocket.SocketHandler;

public class JettyStarter {
	public static void main(String [] args) {
		Server server = new Server();
        ServerConnector connector = new ServerConnector(server);
        connector.setPort(8080);
        server.addConnector(connector);

        // add first handler
        ResourceHandler resource_handler = new ResourceHandler();
        resource_handler.setDirectoriesListed(true);
        resource_handler.setWelcomeFiles(new String[]{ "index.html" });
        resource_handler.setResourceBase(".");

        HandlerList handlers = new HandlerList();
        // first element  is webSocket handler, second element is first handler
        handlers.setHandlers(new Handler[] {new SocketHandler(), resource_handler});
        
        server.setHandler(handlers);

        try {
            server.start();
            server.join();
        } catch (Throwable t) {
            t.printStackTrace(System.err);
        }
	}
}

В классе JettyStarter.java изменения и добавления подсвечены.

SocketHandler.java

package our.task.JettyWebSocket;

import org.eclipse.jetty.websocket.server.WebSocketHandler;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;

public class SocketHandler extends WebSocketHandler {

	@Override
	public void configure(WebSocketServletFactory factory) {
		factory.register(MySocket.class);
	}	
}

MySocket.java

package our.task.JettyWebSocket;

import java.io.IOException;

import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;

@WebSocket
public class MySocket {
	private Session session;
	
	@OnWebSocketConnect
    public void onConnect(Session session) {
        System.out.println("Connect: " + session.getRemoteAddress().getAddress());
        try {
            this.session = session;
            session.getRemote().sendString("Got your connect message");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
	
	@OnWebSocketMessage
    public void onText(String message) {
        System.out.println("text: " + message);
        try {
        	this.session.getRemote().sendString(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
	
	@OnWebSocketClose
    public void onClose(int statusCode, String reason) {
        System.out.println("Close: statusCode=" + statusCode + ", reason=" + reason);       
    }
}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>our.task</groupId>
  <artifactId>JettyWebSocket</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>JettyWebSocket</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
  	<!-- Server, ServerConnector -->
  	<dependency>	
		<groupId>org.eclipse.jetty</groupId>
		<artifactId>jetty-server</artifactId>
		<version>9.1.3.v20140225</version>
	</dependency>
	
	<!-- WebSocketHandler, WebSocketServletFactory -->
	<dependency>
		<groupId>org.eclipse.jetty.websocket</groupId>
		<artifactId>websocket-server</artifactId>
		<version>9.1.3.v20140225</version>
	</dependency>
	
    <dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.11</version>
		<scope>test</scope>
    </dependency>
  </dependencies>
  
  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.3.2</version>
	  </plugin>
	</plugins>
   </build>
</project>

Запуск проекта

После того как все классы добавлены, попробуем запустить проект. Сначала выполним команду mvn install:

mvn install

После этого мавен подтянет все плагины и зависимости:

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building JettyWebSocket 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ JettyWebSocket ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory c:\practice\test1\WebSocketJetty\src\main\resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ JettyWebSocket ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 3 source files to c:\practice\test1\WebSocketJetty\target\classes
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ JettyWebSocket ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory c:\practice\test1\WebSocketJetty\src\test\resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ JettyWebSocket ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ JettyWebSocket ---
[INFO] No tests to run.
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ JettyWebSocket ---
[INFO] Building jar: c:\practice\test1\WebSocketJetty\target\JettyWebSocket-0.0.1-SNAPSHOT.jar
[INFO] 
[INFO] --- maven-install-plugin:2.4:install (default-install) @ JettyWebSocket ---
[INFO] Installing c:\practice\test1\WebSocketJetty\target\JettyWebSocket-0.0.1-SNAPSHOT.jar to C:\Users\zheka\.m2\repository\our\task\JettyWebSocket\0.0.1-SNAPSHOT\JettyWebSocket-0.0.1-SNAPSHOT.jar
[INFO] Installing c:\practice\test1\WebSocketJetty\pom.xml to C:\Users\zheka\.m2\repository\our\task\JettyWebSocket\0.0.1-SNAPSHOT\JettyWebSocket-0.0.1-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.878 s
[INFO] Finished at: 2014-10-16T20:21:16+03:00
[INFO] Final Memory: 14M/156M
[INFO] ------------------------------------------------------------------------
mvn exec:java -Dexec.mainClass="our.task.JettyServer.JettyStarter"
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building JettyWebSocket 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- exec-maven-plugin:1.3.2:java (default-cli) @ JettyWebSocket ---
WARNING Warning: killAfter is now deprecated. Do you need it ? Please comment on MEXEC-6.
Connect: /0:0:0:0:0:0:0:1
text: test
text: test1
text: test2
Close: statusCode=1005, reason=null

Client 1

<button type="button" onclick="WebSocketTest()">Send</button>
<script type="text/javascript">
	function WebSocketTest()
	{
		alert("WebSocket is supported by your Browser!");
		// Let us open a web socket
		var ws = new WebSocket("ws://localhost:8080");
		ws.onopen = function()
		{
			// Web Socket is connected, send data using send()
			ws.send("Message to send");
			alert("Message is sent...");
		};
		ws.onmessage = function (evt)
		{
			var received_msg = evt.data;
			alert("Message is received...");
		};
		ws.onclose = function()
		{
			// websocket is closed.
			alert("Connection is closed...");
		};
	}
 </script>

Client 2

<html>
	<head>
		<meta charset=UTF-8>
		<title>Tomcat WebSocket Chat</title>
		<script>
			var ws = new WebSocket("ws://localhost:8080");
			ws.onopen = function(){
			};
			ws.onmessage = function(message){
				document.getElementById("chatlog").textContent += message.data + "\n";
			};
			function postToServer(){
				ws.send(document.getElementById("msg").value);
				document.getElementById("msg").value = "";
			}
			function closeConnect(){
				ws.close();
			}
		</script>
	</head>
	<body>
		<textarea id="chatlog" readonly></textarea><br/>
		<input id="msg" type="text" />
		<button type="submit" id="sendButton" onClick="postToServer()">Send!</button>
		<button type="submit" id="sendButton" onClick="closeConnect()">End</button>
	</body>
</html>

Ссылки

WebSocket in Jetty
WebSockets — полноценный асинхронный веб

Поделиться в социальных сетях

Опубликовать в Google Plus
Опубликовать в LiveJournal
Опубликовать в Мой Мир
Опубликовать в Одноклассники
Опубликовать в Яндекс

One thought on “Jetty WebSocket (часть 2)

  1. Александр says:

    Отличный материал!

    И «Embedded jetty server (часть 1)» тоже отличный. Все собралось и заработало, несмотря на то, что пришлось немного погуглить по ошибкам мавена. Ошибки были из-за того, что я юзаю Idea и там пришлось вручную вписывать в «Command line» параметр «exec:java».

     

    У меня почему-то сразу закрываются коннекции «Connection is closed». Но это не важно. Ваш материал очень помог в разбирательстве основ Jetty Embedded.

    Спасибо!

    Ответить

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *