WebSocketについていよいよRFCも発行されたので、もう少し本格的にいじってみるかと思い、今さらながらgihyoの記事を参考にJettyでWebSocketを試してみた。 - 特集:Jettyで始めるWebSocket超入門|gihyo.jp … 技術評論社 -- http://gihyo.jp/dev/feature/01/websocket が・・・2010年8-9月頃の記事であるため、Jettyのバージョンが8となり、いろいろ記事のコードでは動かなくなってる。 まずインターフェイスが分離されている。記事ではWebSocketクラス一つをimplementしているが、Jetty 8 ではWebSocket.OnXXYYというように用途別に最低限度必要なinterfaceのみに分離されている。今回はチャットとしてテキストメッセージしか扱わないので、WebSocket.OnTextMessageをWebSocketとあわせてimplementする。 この時点で「こりゃあ、直接jetty-websocketのテストコード漁ったほうが早そうだ」と見切りをつけて、githubからjettyのコードをclone。 以下のテストコードが見つかったので、流用。 - https://github.com/eclipse/jetty.project/blob/master/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/TestServer.java で、特にコンテキストパスとかは設定せずに実装。こんな感じになりました。 webSocketChat.MyWebSocket.java: #code|java|> package webSocketChat; import java.io.IOException; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import org.eclipse.jetty.websocket.WebSocket; public class MyWebSocket implements WebSocket, WebSocket.OnTextMessage { Connection conn; static Set _connections = new CopyOnWriteArraySet(); public void onOpen(Connection paramConnection) { conn = paramConnection; synchronized (_connections) { _connections.add(this); } } public void onClose(int paramInt, String paramString) { synchronized (_connections) { _connections.remove(this); } } public void onMessage(String paramString) { for (MyWebSocket c : _connections) { try { c.conn.sendMessage(paramString); } catch (IOException e) { e.printStackTrace(); } } } } ||< webSocketChat.MyWebSocketServer.java: #code|java|> package webSocketChat; import javax.servlet.http.HttpServletRequest; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ResourceHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.websocket.WebSocket; import org.eclipse.jetty.websocket.WebSocketHandler; public class MyWebSocketServer extends Server { SelectChannelConnector _connector; WebSocketHandler _wsHandler; ResourceHandler _rsHandler; public MyWebSocketServer(int port, String dir) { _connector = new SelectChannelConnector(); _connector.setPort(port); addConnector(_connector); _wsHandler = new WebSocketHandler() { public WebSocket doWebSocketConnect( HttpServletRequest paramHttpServletRequest, String paramString) { System.out.printf("protocol=%s¥n", paramString); return new MyWebSocket(); } }; _rsHandler = new ResourceHandler(); _rsHandler.setDirectoriesListed(true); _rsHandler.setResourceBase(dir); _wsHandler.setHandler(_rsHandler); setHandler(_wsHandler); } private static void usage() { System.err.println("java -cp CLASSPATH " + MyWebSocketServer.class + " [ OPTIONS ]"); System.err.println(" -p|--port PORT (default 8080)"); System.err.println(" -d|--docroot file (default 'src/main/resources/html')"); System.exit(1); } public static void main(String... args) throws Exception { int port = 8080; String docroot = "src/main/resources/html"; for (int i = 0; i < args.length; i++) { String a = args[i]; if ("-p".equals(a) || "--port".equals(a)) port = Integer.parseInt(args[++i]); else if ("-d".equals(a) || "--docroot".equals(a)) docroot = args[++i]; else if (a.startsWith("-")) usage(); } MyWebSocketServer server = new MyWebSocketServer(port, docroot); server.start(); server.join(); } } ||< で、HTMLファイルはどんなのを用意したかというと、こちらはGoogleのpywebsocketからそのままごっそりコピペ。 - http://code.google.com/p/pywebsocket/source/browse/trunk/src/example/console.html で、継ぎ接ぎだらけですが曲がりなりにもチャットが動きました。 JettyとWebSocket、両方勉強できて一石二鳥かとも思ったんですが、Jettyの構造とか使い方もう少し勉強しないとダメですね・・・。