読者です 読者をやめる 読者になる 読者になる

感謝のプログラミング 10000時間

たどり着いた結果(さき)は、感謝でした。

Jettyを使って、JavaでWebSocketサーバーを実装してみる。

<スポンサーリンク>

WebSocketって何?

WebSocketとは、サーバとクライアントの間で降雨率的な双方向通信を実現するための仕組みである。
WebSocketを利用すると、1本のHTTP接続上で双方向のメッセージを自由にやりとりできる。
HTTPのリクエスト、リプライでは実現できなかった、「サーバーからのpush通信」もWebSocketを使えば実現可能となる。

JettyでWebSocketを実装するサンプル

昨日から、Javaを使ってWebSocketサーバーを作ろうと考え、WebSocketをサポートしているJettyというアプリケーションサーバに光を当てた。
で、Eclipseのプラグインまでインストールしたのが以下の記事。
http://d.hatena.ne.jp/sho322/20130714/1373823115

今日はその環境を使って、JettyでWebSocketを実装し、チャットシステムを作ってみる。

まず、Eclipseで「新規プロジェクト」→「Web」→「動的Webプロジェクト」、で適当にプロジェクトを作る。
今回は「websocketsample」とした。

で、動的Webプロジェクトを作ったらできる「WEB-INF/lib」以下に、ダウンロードしたJettyのlibに入っているjarを大量にコピーした。
「\jetty-distribution-7.6.7.v20120910\lib」以下のもの。
コピーするとそのままビルドパスに追加されたようで、普通に
「org.eclipse.jetty.websocket.WebSocketServlet」などをインポートできるようになった。

サーバサイドの実装

まずは、リクエストを受け取るサーブレットの部分。

package sample;

import javax.servlet.http.HttpServletRequest;

import org.eclipse.jetty.websocket.WebSocket;
import org.eclipse.jetty.websocket.WebSocketServlet;

public class EchoServlet extends WebSocketServlet {

	@Override
	public WebSocket doWebSocketConnect(HttpServletRequest req, String protocol) {
		System.out.println("リクエストを受け取りました!");
		return new EchoWebSocket();
	}

}

jettyでWebSocketを実装するには、WebSocketServletを継承したサーブレットを作る。
リクエストを受け取ったら、doWebSocketConnectが呼び出される。

で、呼び出された時にインスタンス化しているEchoWebSocketがこちら。

package sample;

import java.io.IOException;

import org.eclipse.jetty.websocket.WebSocket;

public class EchoWebSocket implements WebSocket.OnTextMessage  {
	private Connection connection;

	@Override
	public void onOpen(Connection connection) {
		System.out.println("コネクションが開かれました!");
		this.connection = connection;
		try {
			connection.sendMessage("hello! I am server!");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void onMessage(String data) {
		try {
			System.out.println("メッセージが届きました!");
			System.out.println("メッセージはこちら!:" + data);
			connection.sendMessage("Echo: " + data);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void onClose(int closeCode, String message) {
		System.out.println("コネクションが閉じられました!");
		if (connection != null) {
			connection.close();
		}
	}
}

WebSocket.OnTextMessageをimplementsする。
コネクションが開かれるとonOpenが呼ばれる。
メッセージを受信するとonMessageが呼ばれる。
閉じるとonCloseが呼ばれる。

実際にサンプルでメッセージを送ったりすると、onMessageのところのコメントが表示された。

WEB-INF直下のweb.xmlはこんな感じで書いた。

<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
	<servlet>
		<servlet-name>Sample</servlet-name>
		<servlet-class>sample.EchoServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>Sample</servlet-name>
		<url-pattern>/sample</url-pattern>
	</servlet-mapping>

</web-app>

さて、ここまででサーバー側は準備OKだ。
次に作るのはクライアントサイドのJavaScriptだ。
ちなみに、WebSocketでは同一オリジン制約は適用されない。
なので、Apacheの80番ポートから8888番などで待ち受けているWebSocketサーバーと直接通信可能である。

以下がクライアントのコードである。

<html>
<head>
	<meta charset="utf-8">
	<title>WebScoketでエコーしてみる</title>
	<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
	<script>
		$(document).ready(function() {
			//WebSocketのコネクションを確立する
			var ws = new WebSocket('ws://localhost:8888/websocketsample/sample');
			console.log("wsオブジェクトを作成!");
			ws.open = function(event) {
				console.log('コネクションが確立されました!');
				ws.send('Hello, WebSocket!');
				console.log('とりあえずメッセージを送信してみました!');
			}

			$('#do').click(function() {
				console.log("do");
				var inputComment = $('form input:text').val();
				console.log(inputComment);
				ws.send(inputComment);
			});

			ws.onmessage = function(event) {
				console.log('メッセージを受け取りました!');
				var recMessage = event.data;
				console.log(recMessage);
				$('#result').append(recMessage + '<br>');
			}
		});
	</script>
</head>
<body>
<h1>WebSocketでエコーチャットするサンプル</h1>
<form>
	<input type="text" id="message" required>
	<input type="button" id="do" value="送信">
</form>
<hr>
<div id="result"></div>
</body>
</html>

テキストボックスに適当に何かを入力すると、それがやまびこのようになって返ってくる。
で、返ってきたメッセージを
ws.onmessageの部分で取得して、ブラウザにリアルタイムで表示している。

参考にした本

パーフェクトJavaScript (PERFECT SERIES 4)

パーフェクトJavaScript (PERFECT SERIES 4)


WebSocketの詳しい説明が載っている。

感謝のプログラミング

今回で感謝のプログラミングは【530時間目】
10000時間まで、あと【9470時間】