1. 소개

  • 웹소켓이란? 
  • Jetty에서 WebSocket을 사용하기 위한 예제
  • Jetty 9 기준
  • 참고 사이트 : https://github.com/jetty-project/embedded-jetty-websocket-examples/tree/master/native-jetty-websocket-example/src/main/java/org/eclipse/jetty/demo

2. 프로젝트

메이븐 프로젝트 기반이다. 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>io.sarc</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>
    <jetty.version>9.2.11.v20150529</jetty.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
	<dependency>
      <groupId>org.eclipse.jetty</groupId>
	  <artifactId>jetty-server</artifactId>
      <version>${jetty.version}</version>
	</dependency>
	<dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-servlet</artifactId>
      <version>${jetty.version}</version>
	</dependency>
	<dependency>
      <groupId>org.eclipse.jetty.websocket</groupId>
      <artifactId>javax-websocket-server-impl</artifactId>
      <version>${jetty.version}</version>
	</dependency>
	<dependency>
      <groupId>org.eclipse.jetty.websocket</groupId>
      <artifactId>websocket-server</artifactId>
      <version>${jetty.version}</version>
	</dependency>
	<dependency>
      <groupId>org.eclipse.jetty.websocket</groupId>
      <artifactId>javax-websocket-client-impl</artifactId>
      <version>${jetty.version}</version>
	</dependency>
	<dependency>
      <groupId>org.eclipse.jetty.websocket</groupId>
      <artifactId>websocket-client</artifactId>
      <version>${jetty.version}</version>
	</dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.0.0</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <mainClass>io.sarc.jettywebsocket.WSServer</mainClass>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

pom.xml 파일의 build 부분은 무시해도 된다.


3. 코드

총 4개의 코드로 구성되어 있다.

3-1. WSServer

package io.sarc.jettywebsocket;
 
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
 
public class WSServer {
  public static void main(String[] args) {
    Server server = new Server();
    ServerConnector connector = new ServerConnector(server);
    connector.setPort(8080);
    server.addConnector(connector);
 
    ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
    context.setContextPath("/");
    server.setHandler(context);
 
    ServletHolder holderEvents = new ServletHolder("ws-tests", WSServlet.class);
    context.addServlet(holderEvents, "/wstest/*");
 
    try {
      server.start();
      server.dump(System.err);
      server.join();
    } catch ( Throwable t ) {
      t.printStackTrace(System.err);
    }
  }
}

3-2. WSSocket

package io.sarc.jettywebsocket;
 
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
 
public class WSSocket extends WebSocketAdapter {
  @Override
  public void onWebSocketConnect(Session sess) {
    super.onWebSocketConnect(sess);
    System.out.println("- Socket Connected: " + sess);
  }
 
  @Override
  public void onWebSocketText(String message) {
    super.onWebSocketText(message);
    System.out.println("- Received Text message: " + message);
  }
 
  @Override
  public void onWebSocketClose(int statusCode, String reason) {
    super.onWebSocketClose(statusCode, reason);
    System.out.println("- Socket Closed: [" + statusCode + "] " + reason);
  }
 
  @Override
  public void onWebSocketError(Throwable cause) {
    super.onWebSocketError(cause);
    cause.printStackTrace(System.err);
  }
}

3-3. WSServlet

package io.sarc.jettywebsocket;
 
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
 
@SuppressWarnings("serial")
public class WSServlet extends WebSocketServlet {
  @Override
  public void configure(WebSocketServletFactory factory) {
    factory.register(WSSocket.class);
  }
}

3-4. WSClient

package io.sarc.jettywebsocket;
 
import java.net.URI;
import java.util.concurrent.Future;
 
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.client.WebSocketClient;
 
public class WSClient {
  public static void main(String[] args) {
    URI uri = URI.create("ws://localhost:8080/wstest/");
 
    WebSocketClient client = new WebSocketClient();
    try {
      try {
        client.start();
        WSSocket socket = new WSSocket();
        Future<session> future = client.connect(socket, uri);
        Session session = future.get();
        session.getRemote().sendString("Hello, sarc.io!");
        session.close();
      } finally {
        client.stop();
      }
    } catch ( Throwable t ) {
      t.printStackTrace(System.err);
    }
  }
}</session>


4. 테스트

4-1.  WSServer 실행

대기 중

4-2. WSClient 실행

2018-05-01 23:49:55.631:INFO::main: Logging initialized @131ms
- Socket Connected: WebSocketSession[websocket=JettyListenerEventDriver[io.sarc.jettywebsocket.WSSocket],behavior=CLIENT,connection=WebSocketClientConnection@49ef82ec{IDLE}{f=Flusher[queueSize=0,aggregateSize=0,failure=null],g=Generator[CLIENT,validating],p=Parser@580d8488[ExtensionStack,s=START,c=0,len=0,f=null,p=WebSocketPolicy@43b5e282[behavior=CLIENT,maxTextMessageSize=65536,maxTextMessageBufferSize=32768,maxBinaryMessageSize=65536,maxBinaryMessageBufferSize=32768,asyncWriteTimeout=60000,idleTimeout=300000,inputBufferSize=4096]]},remote=WebSocketRemoteEndpoint@5faa27[batching=true],incoming=JettyListenerEventDriver[io.sarc.jettywebsocket.WSSocket],outgoing=ExtensionStack[queueSize=0,extensions=[],incoming=org.eclipse.jetty.websocket.common.WebSocketSession,outgoing=org.eclipse.jetty.websocket.client.io.WebSocketClientConnection]]
- Socket Closed: [1001] Shutdown

4-3. WSServer 확인

- Socket Connected: WebSocketSession[websocket=JettyListenerEventDriver[io.sarc.jettywebsocket.WSSocket],behavior=SERVER,connection=WebSocketServerConnection@16ec75ac{IDLE}{f=Flusher[queueSize=0,aggregateSize=0,failure=null],g=Generator[SERVER,validating],p=Parser@3be2f06b[ExtensionStack,s=START,c=0,len=0,f=null,p=WebSocketPolicy@4148ea7d[behavior=SERVER,maxTextMessageSize=65536,maxTextMessageBufferSize=32768,maxBinaryMessageSize=65536,maxBinaryMessageBufferSize=32768,asyncWriteTimeout=60000,idleTimeout=300000,inputBufferSize=4096]]},remote=WebSocketRemoteEndpoint@7eac0734[batching=true],incoming=JettyListenerEventDriver[io.sarc.jettywebsocket.WSSocket],outgoing=ExtensionStack[queueSize=0,extensions=[],incoming=org.eclipse.jetty.websocket.common.WebSocketSession,outgoing=org.eclipse.jetty.websocket.server.WebSocketServerConnection]]
- Received Text message: Hello, sarc.io!
- Socket Closed: [1000] null

5. HTML Client로 테스트

서버는 그대로 두고 HTML 기반의 Client를 통해 테스트한다. 다음은 HTML Client 예제이다.

<!DOCTYPE HTML>
<html>
   <head>
      <script type = "text/javascript">
         function WebSocketTest() {
 
            if ("WebSocket" in window) {
               alert("WebSocket is supported by your Browser!");
 
               var ws = new WebSocket("ws://localhost:8080/wstest");
 
               ws.onopen = function() {
                  ws.send("My message");
                  alert("Message is sent...");
               };
 
               ws.onmessage = function (evt) {
                  var received_msg = evt.data;
                  alert("Message is received...");
               };
 
               ws.onclose = function() {
                  alert("Connection is closed...");
               };
            } else {
               alert("WebSocket NOT supported by your Browser!");
            }
         }
      </script>
   </head>
   <body>
      <div id = "sse">
         <a href = "javascript:WebSocketTest()">Run WebSocket</a>
      </div>
   </body>
</html>