第15章 WebSocket アプリケーションの作成
WebSocket プロトコルは、Web クライアントとサーバー間の双方向通信を提供します。クライアントとサーバー間の通信はイベントベースであるため、ポーリングベースの通信よりも処理が高速になり、帯域幅が小さくなります。WebSocket は、JavaScript API を用いて Web アプリケーションで使用したり、Java Websocket API を用いてクライアント WebSocket エンドポイントで使用したりできます。
最初に接続はクライアントとサーバー間で HTTP 接続として確立されます。その後、クライアントは Upgrade
ヘッダーを使用して WebSocket 接続を要求します。同じ TCP/IP 接続上ではすべて全二重通信になり、データのオーバヘッドが最小化されます。各メッセージには不必要な HTTP ヘッダーコンテンツが含まれていないため、Websocket 通信で必要な帯域幅は小さくなります。その結果、通信パスのレイテンシーが低くなるため、リアルタイムの応答が必要なアプリケーションに適しています。
JBoss EAP WebSocket 実装は、サーバーエンドポイントに対して完全な依存関係注入サポートを提供しますが、クライアントエンドポイントに対して CDI サービスを提供しません。
WebSocket アプリケーションには以下のコンポーネントと設定変更が必要です。
- Java クライアントまたは WebSocket が有効になっている HTML クライアント。HTML クライアントのブラウザーのサポートについては http://caniuse.com/websockets で確認できます。
- WebSocket サーバーエンドポイントクラス。
- WebSocket API で依存関係を宣言するために設定されたプロジェクト依存関係。
WebSocket アプリケーションの作成
以下のコード例は、JBoss EAP に同梱される websocket-hello
クイックスタートの一部です。これは、接続を開き、メッセージを送信し、接続を閉じる WebSocket アプリケーションの単純な例です。他の機能を実装せず、実際のアプリケーションで必要となるエラー処理を含みません。
JavaScript HTML クライアントを作成します。
以下は WebSocket クライアントの例になります。この例には 3 つの JavaScript 関数が含まれています。
-
connect()
: この関数は WebSocket URI を渡す WebSocket 接続を作成します。リソースの場所は、サーバーエンドポイントクラスに定義されたリソースと一致します。この関数は、WebSocket のonopen
、onmessage
、onerror
、およびonclose
もインターセプトし、処理します。 -
sendMessage()
: この関数はフォームに入力された名前を取得し、メッセージを作成します。さらに、WebSocket.send() コマンドを使用してメッセージを送信します。 -
disconnect()
: この関数は WebSocket.close() コマンドを実行します。 -
displayMessage()
: この関数は、ページ上の表示メッセージを WebSocket エンドポイントメソッドによって返された値に設定します。 displayStatus()
: この関数は WebSocket の接続状態を表示します。アプリケーションの index.html コード例
<html> <head> <title>WebSocket: Say Hello</title> <link rel="stylesheet" type="text/css" href="resources/css/hello.css" /> <script type="text/javascript"> var websocket = null; function connect() { var wsURI = 'ws://' + window.location.host + '/jboss-websocket-hello/websocket/helloName'; websocket = new WebSocket(wsURI); websocket.onopen = function() { displayStatus('Open'); document.getElementById('sayHello').disabled = false; displayMessage('Connection is now open. Type a name and click Say Hello to send a message.'); }; websocket.onmessage = function(event) { // log the event displayMessage('The response was received! ' + event.data, 'success'); }; websocket.onerror = function(event) { // log the event displayMessage('Error! ' + event.data, 'error'); }; websocket.onclose = function() { displayStatus('Closed'); displayMessage('The connection was closed or timed out. Please click the Open Connection button to reconnect.'); document.getElementById('sayHello').disabled = true; }; } function disconnect() { if (websocket !== null) { websocket.close(); websocket = null; } message.setAttribute("class", "message"); message.value = 'WebSocket closed.'; // log the event } function sendMessage() { if (websocket !== null) { var content = document.getElementById('name').value; websocket.send(content); } else { displayMessage('WebSocket connection is not established. Please click the Open Connection button.', 'error'); } } function displayMessage(data, style) { var message = document.getElementById('hellomessage'); message.setAttribute("class", style); message.value = data; } function displayStatus(status) { var currentStatus = document.getElementById('currentstatus'); currentStatus.value = status; } </script> </head> <body> <div> <h1>Welcome to Red Hat JBoss Enterprise Application Platform!</h1> <div>This is a simple example of a WebSocket implementation.</div> <div id="connect-container"> <div> <fieldset> <legend>Connect or disconnect using websocket :</legend> <input type="button" id="connect" onclick="connect();" value="Open Connection" /> <input type="button" id="disconnect" onclick="disconnect();" value="Close Connection" /> </fieldset> </div> <div> <fieldset> <legend>Type your name below, then click the `Say Hello` button :</legend> <input id="name" type="text" size="40" style="width: 40%"/> <input type="button" id="sayHello" onclick="sendMessage();" value="Say Hello" disabled="disabled"/> </fieldset> </div> <div>Current WebSocket Connection Status: <output id="currentstatus" class="message">Closed</output></div> <div> <output id="hellomessage" /> </div> </div> </div> </body> </html>
-
WebSocket サーバーエンドポイントを作成します。
以下の方法のいずれかを使用して WebSocket サーバーエンドポイントを作成できます。
- プログラム的なエンドポイント(Programmatic Endpoint): エンドポイントは Endpoint クラスを拡張します。
-
アノテーション付きエンドポイント
): エンドポイントクラスはアノテーションを使用して WebSocket イベントと対話します。これは、プログラム的なエンドポイントよりも簡単にコーティングできます。
以下のコード例では、アノテーション付きエンドポイントが使用され、以下のイベントが処理されます。
-
@ServerEndpoint
アノテーションは、このクラスを WebSocket サーバーエンドポイントとして識別し、パスを指定します。 -
WebSocket 接続が開かれると
@OnOpen
アノテーションがトリガーされます。 -
メッセージが受信されると、
@OnMessage
アノテーションがトリガーされます。 WebSocket 接続が閉じられると、
@OnClose
アノテーションがトリガーされます。WebSocket エンドポイントのコード例
package org.jboss.as.quickstarts.websocket_hello; import javax.websocket.CloseReason; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/websocket/helloName") public class HelloName { @OnMessage public String sayHello(String name) { System.out.println("Say hello to '" + name + "'"); return ("Hello" + name); } @OnOpen public void helloOnOpen(Session session) { System.out.println("WebSocket opened: " + session.getId()); } @OnClose public void helloOnClose(CloseReason reason) { System.out.println("WebSocket connection closed with CloseCode: " + reason.getCloseCode()); } }
プロジェクト POM ファイルで WebSocket API の依存関係を宣言します。
Maven を使用する場合は、プロジェクト
pom.xml
ファイルに以下の依存関係を追加します。Maven 依存関係の例
<dependency> <groupId>org.jboss.spec.javax.websocket</groupId> <artifactId>jboss-websocket-api_1.0_spec</artifactId> <version>1.0.0.Final</version> <scope>provided</scope> </dependency>
JBoss EAP に同梱されるクイックスタートには、追加の WebSocket クライアントとエンドポイントのコード例が含まれます。