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>