Java で WebSocket を扱おうとすると、javax.websocketの使い方に関する記事がかなりヒットするのですが(Google 日本語検索だとね)、正直言って、もっとライトに試してみたいというのが本音。
"java websocket" を Google 英語検索すると、以下のライブラリがトップに出ました。
こいつがかなり手軽に Java Websocket を書けそうなものだったので試してみました。
Java-WebSocket とは
java.nio が提供する non-blocking イベントドリブンモデルを利用した、100% Java で書かれている WebSocket Server だそうです。
java.nio って non-blocking な IO が可能なんですね。
恥ずかしながら初めて知りました。
参考
サポートされている WebSocket プロトコルのバージョンはこちらだそうです。
Build
Ant か maven でビルドできます。
今回は maven を使います。
早速動かしてみましょう。
まずはビルド。
% git clone git@github.com:TooTallNate/Java-WebSocket.git
% cd Java-WebSocket
% mvn package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Java WebSocket 1.3.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 53.567 s
[INFO] Finished at: 2016-05-28T17:46:00+09:00
[INFO] Final Memory: 25M/206M
[INFO] ------------------------------------------------------------------------
オーケー。
続いてデモっぽいのを動かしてみます。
% java -cp build/examples:dist/java_websocket.jar ChatServer
エラー: メイン・クラスChatServerが見つからなかったかロードできませんでした
むむむ・・・。
maven からビルドした場合は、サンプルないのかな??
残念です。
しかしながら、あまり難しくはなさそうなので、自分で WebSocket サーバを実装してみます。
WebSocketServer の書き方
org.java_websocket.server.WebSocketServer
抽象クラスを継承して、コードを付け足すことでできるそうです。
WebSocketClient の書き方
org.java_websocket.server.WebSocketServer
抽象クラスを継承して、コードを付け足すことでできるそうです。
WSS Support
面倒臭いので飛ばします。
またの機会に・・・。
実際に書いてみる
WebSocketServer
まずはこいつの jar を取得します。
Maven にあったので、それを使います。
% curl -OL http://central.maven.org/maven2/org/java-websocket/Java-WebSocket/1.3.0/Java-WebSocket-1.3.0.jar
続いて、コードを書きます。
こちらを参考にします。
コピーペーストしてちょっとだけ編集したのがこちら。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Collection;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
public class ChatServer extends WebSocketServer {
public ChatServer( int port ) throws UnknownHostException {
super ( new InetSocketAddress( port ) );
}
@Override
public void onOpen( WebSocket connection, ClientHandshake handshake ) {
System.out.println( connection.getRemoteSocketAddress().getAddress().getHostAddress() + " entered the room!" );
}
@Override
public void onClose( WebSocket connection, int code, String reason, boolean remote ) {
System.out.println( connection + " has left the room!" );
}
@Override
public void onMessage( WebSocket connection, String message ) {
System.out.println( connection + ": " + message );
Collection<WebSocket> websockets = connections();
synchronized ( websockets ) {
for ( WebSocket websocket: websockets ) {
websocket.send(message);
}
}
}
@Override
public void onError( WebSocket connection, Exception e ) {
e.printStackTrace();
}
public static void main( String[] args ) throws InterruptedException, IOException {
ChatServer server = new ChatServer( 8887 );
server.start();
System.out.println( "ChatServer started on port: " + server.getPort() );
}
}
コンパイル
% javac -cp Java-WebSocket-1.3.0.jar ChatServer.java
WebSocketClient
こいつは、ブラウザの WebSocket を用いることにしました。
<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<title>Sample client of Java_WebSocket_Sample</title>
</head>
<script>
var websocket = new WebSocket("ws://localhost:8887");
websocket.onopen = function () {
console.log("Connection is opened!");
};
websocket.onclose = function () {
console.log("Connection is closed!");
};
websocket.onmessage = function (e) {
console.log(e);
var data = JSON.parse(e.data);
var slMessage = d3.select("#messages").append("div")
.attr("class", "message")
;
slMessage.append("span").attr("class", "name").text(data.name + ":");
slMessage.append("span").attr("class", "say").text(data.say);
};
websocket.onerror = function () {
console.log("Error is occured!");
};
window.addEventListener("load", function () {
d3.select("#name")[0][0].value = "名無しのごんべえ";
d3.select("#post").on("click", function () {
var say = d3.select("#say")[0][0].value;
var name = d3.select("#name")[0][0].value;
if (say.length === 0) { return ; }
d3.select("#say")[0][0].value = "";
websocket.send(JSON.stringify({say: say, name: name}));
});
});
</script>
<body>
<input type="text" id="name"></input>
<input type="text" id="say" placeholder="Say something!!"></input>
<button type="text" id="post">say</button>
<div id="messages">
</div>
</body>
</html>
テスト
サーバ起動します
% java -cp .:Java-WebSocket-1.3.0.jar ChatServer
ChatServer started on port: 8887
タブを2つ開きます
メッセージを入れてみましょう
どうやらうまく動いたようです
ちなみにサーバ側の標準出力はこちら。
% java -cp .:Java-WebSocket-1.3.0.jar ChatServer
ChatServer started on port: 8887
0:0:0:0:0:0:0:1 entered the room!
0:0:0:0:0:0:0:1 entered the room!
org.java_websocket.WebSocketImpl@6207ffd1: {"say":"こっぱみじんにしてやる。","name":"⭕️りーざ"}
org.java_websocket.WebSocketImpl@6207ffd1: {"say":"あの地球人のようになぁ・・・","name":"⭕️りーざ"}
org.java_websocket.WebSocketImpl@6207ffd1: {"say":"ふっふっふっふっふっふ・・・","name":"⭕️りーざ"}
org.java_websocket.WebSocketImpl@6cb09aae: {"say":"あの地球人のようにだと?!","name":"⭕️くう"}
org.java_websocket.WebSocketImpl@6cb09aae: {"say":"クリリンのことか!","name":"⭕️くう"}
org.java_websocket.WebSocketImpl@6cb09aae: {"say":"クリリンのことかーーー!!","name":"⭕️くう"}
java にしてはすばらしく手軽ですが、本番運用に耐えうるライブラリかどうか?というとそれはわかりませんね・・・。