1.WebSocketとは何ですか?
WebSocket は、自然な全二重、双方向、単一ソケット接続です。 WebSocket を使用すると、HTTP リクエストは WebSocket 接続 (WebSocket または TLS (Transport Layer Security、旧称「SSL」) 上の WebSocket) を開く単一のリクエストとなり、クライアントからサーバーへ、およびサーバーからクライアントへ同じ接続を再利用します。 WebSocket 接続が確立されると、サーバーはメッセージが利用可能になったときにメッセージを送信できるため、WebSocket によって待ち時間が短縮されます。たとえば、ポーリングとは異なり、WebSocket は 1 つのリクエストのみを行います。サーバーはクライアントからのリクエストを待つ必要はありません。同様に、クライアントはいつでもサーバーにメッセージを送信できます。利用可能なメッセージがあるかどうかに関係なく、時々リクエストをポーリングして送信する場合と比較して、単一のリクエストにより待ち時間が大幅に短縮されます。
2. WebSocket API
WebSocket API を使用すると、Web を介してクライアント アプリケーションとサーバー側のプロセス間の全二重双方向通信を確立できます。 WebSocket インターフェイスは、クライアントが使用できるメソッドと、クライアントがネットワークと対話する方法を指定します。
3. WebSocket コンストラクター
サーバーへの WebSocket 接続を確立するには、WebSocket インターフェイスを使用して、接続するエンドポイントを表す URL を指定して WebSocket オブジェクトをインスタンス化します。 WebSocket プロトコルは、ws と wss という 2 つの URL スキームを定義しており、クライアントとサーバー間の暗号化されていないトラフィックと暗号化されたトラフィックにそれぞれ使用されます。
例: var ws = new WebSocket("ws://www.websocket.org");
4. WebSocket イベント
WebSocket API は純粋にイベント駆動型です。アプリケーション コードは、受信データと接続状態の変更を処理するために、WebSocket オブジェクト上のイベントをリッスンします。 WebSocket プロトコルもイベント駆動型です。
WebSocket オブジェクトは 4 つの異なるイベントを送出します:
A. open イベント:
サーバーが WebSocket 接続要求に応答すると、open イベントがトリガーされ、接続が確立されます。 open イベントに対応するコールバック関数は onopen
と呼ばれます。例:
ws.onopen = function(e) { console.log("Connection open..."); };
B. メッセージ イベント: メッセージが受信されると
message イベントがトリガーされ、このイベントに対応するコールバック関数は onmessage です。 。
インスタンス:
ws.onmessage = function(e) { if(typeof e.data === "string"){ console.log("String message received", e, e.data); } else { console.log("Other message received", e, e.data); } };
C. エラーイベント:
error イベントは、予期しない障害に応じてトリガーされます。このイベントに対応するコールバック関数は onerror です。
例:
ws.onerror = function(e){ console.log('websocked error'); handerError(); }
D. close イベント:
close イベントは、WebSocket 接続が閉じられるとトリガーされます。 close イベントに対応するコールバック関数は onclose です。
例:
ws.onclose = function(e) { console.log("Connection closed", e); };
5. WebSocket メソッド
WebSocket オブジェクトには、send() と close() の 2 つのメソッドがあります。
A. send() メソッド:
WebSocket を使用してクライアントとサーバー間の全二重双方向接続を確立した後、接続が開かれたときに send() メソッドを呼び出すことができます。 send() メソッドを使用して、クライアントからサーバーにメッセージを送信します。 1 つ以上のメッセージを送信した後、接続を開いたままにすることも、close() メソッドを呼び出して接続を終了することもできます。
例:
ws.send("Hello WebSocket!");
B. close() メソッド:
WebSocket 接続を閉じるか、接続試行を終了するには、close() メソッドを使用します。接続が閉じられている場合、このメソッドは何も行いません。 close() を呼び出した後は、閉じられた WebSocket ではデータを送信できません。 close() メソッドには、code (数値ステータス コード) とreason (テキスト文字列) という 2 つのオプションのパラメータを渡すことができます。これらのパラメータを渡すと、クライアントが接続を閉じた理由に関する情報をサーバーに伝えることができます。
注: 上記は WebSocket の簡単な紹介です。以下では、WebSocket の使用方法を紹介するために、簡単な Web ページのリアルタイム チャットのケースを使用します
A: まず、新しいプロジェクトを作成します。ここではチャットルームと呼びます。パッケージを作成し、使用する新しいクラスを作成します。 サーバー側の接続を実現するためのクラス名は ChatWebSocketServlet.Java です。
具体的なプロジェクト構造は次のとおりです。
B: サーバー側の実装クラスを作成します。 ChatWebSocketServlet.java、具体的なコードは次のとおりです:
package com.yc.chat.Servlet; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Set; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import org.apache.catalina.websocket.MessageInbound; import org.apache.catalina.websocket.StreamInbound; import org.apache.catalina.websocket.WebSocketServlet; import org.apache.catalina.websocket.WsOutbound; @WebServlet("/chat") public class ChatWebSocketServlet extends WebSocketServlet { private final Map<Integer, WsOutbound> map = new HashMap<Integer, WsOutbound>(); private static final long serialVersionUID = -1058445282919079067L; @Override protected StreamInbound createWebSocketInbound(String arg0, HttpServletRequest request) { // StreamInbound:基于流的WebSocket实现类(带内流),应用程序应当扩展这个类并实现其抽象方法onBinaryData和onTextData。 return new ChatMessageInbound(); } class ChatMessageInbound extends MessageInbound { // MessageInbound:基于消息的WebSocket实现类(带内消息),应用程序应当扩展这个类并实现其抽象方法onBinaryMessage和onTextMessage。 @Override protected void onOpen(WsOutbound outbound) { map.put(outbound.hashCode(), outbound); super.onOpen(outbound); } @Override protected void onClose(int status) { map.remove(getWsOutbound().hashCode()); super.onClose(status); } @Override protected void onBinaryMessage(ByteBuffer buffer) throws IOException { } @Override protected void onTextMessage(CharBuffer buffer) throws IOException { String msg = buffer.toString(); Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); msg = " <font color=green>匿名用戶 " + sdf.format(date) + "</font><br/> " + msg; broadcast(msg); } private void broadcast(String msg) { Set<Integer> set = map.keySet(); for (Integer integer : set) { WsOutbound outbound = map.get(integer); CharBuffer buffer = CharBuffer.wrap(msg); try { outbound.writeTextMessage(buffer); outbound.flush(); } catch (IOException e) { e.printStackTrace(); } } } } }
C : フロントエンドページのindex.jspを実装します(関数を表示するために美化されていません。具体的なコードは比較的単純です)。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>websocket聊天室</title> <style type="text/css"> #chat { text-align: left; width: 600px; height: 500px; width: 600px; } #up { text-align: left; width: 100%; height: 400px; border: 1px solid green; OVERFLOW-Y: auto; } #down { text-align: left; height: 100px; width: 100%; } </style> </head> <body> <h2 align="center">基于HTML5的聊天室</h2> <div align="center" style="width: 100%; height: 700px;"> <div id="chat"> <div id="up"></div> <div id="down"> <textarea type="text" style="width: 602px; height: 100%;" id="send"></textarea> </div> </div> <input type="button" value="连接" onclick="chat(this);"> <input type="button" value="发送" onclick="send(this);" disabled="disabled" id="send_btn" title="Ctrl+Enter发送"> </div> </body> <script type="text/javascript"> var socket; var receive_text = document.getElementById("up"); var send_text = document.getElementById("send"); function addText(msg) { receive_text.innerHTML += "<br/>" + msg; receive_text.scrollTop = receive_text.scrollHeight; } var chat = function(obj) { obj.disabled = "disabled"; socket = new WebSocket('ws://localhost:8080/chatroom/chat'); receive_text.innerHTML += "<font color=green>正在连接服务器……</font>"; //打开Socket socket.onopen = function(event) { addText("<font color=green>连接成功!</font>"); document.getElementById("send_btn").disabled = false; send_text.focus(); document.onkeydown = function(event) { if (event.keyCode == 13 && event.ctrlKey) { send(); } } }; socket.onmessage = function(event) { addText(event.data); }; socket.onclose = function(event) { addText("<font color=red>连接断开!</font>"); obj.disabled = ""; }; if (socket == null) { addText("<font color=red>连接失败!</font>"); } }; var send = function(obj) { if (send_text.value == "") { return; } socket.send(send_text.value); send_text.value = ""; send_text.focus(); } </script> </html>
このような単純なリアルタイム チャット ページが準備できました。次に、プロジェクトを Tomcat 7.0 サーバーにデプロイし、サーバーを開いてチャット
結果を表示します。アドレスバーのサーバーアドレス:
http://127.0.0.1:8080/chatroom/index.jsp
クリックしてサーバーに接続すると、結果は次のようになります:
2. 2 つの異なるファイルを開きます。ブラウザを使用して相互にメッセージを送信します (ここでは Google と Firefox を使用します)。結果は次のとおりです: