「WebSocket」はTCPのソケットのようなプロトコルで、サーバーとクライアント間の双方向通信が可能です。HTTP/2 Clientでも、もちろんWebSocketをサポートしています。HTTP/2 Clientの最終回は、このWebSocketを簡単なチャットシステムを作りながら紹介していきます。

 HTTPを使用した通信では、クライアントがサーバに対してリクエストを送信すると、サーバーがレスポンスを返します。これとは逆に、クライアントからのリクエストがない状態で、サーバーからクライアントへデータを送信することはできません。

 しかし、サーバーからクライアントへリアルタイムにデータを送信したい場合は多々あります。例えば、ECサイトではどうでしょう。リアルタイムに商品が在庫しているかどうか表示できないと、ユーザーがカートに商品を入れようとしたときになって初めて在庫がないことが分かります。これではサイトの使い勝手が悪くなってしまいます。

 そこで、ロングポーリングを利用した「Comet」などの技術を使用して疑似的にサーバーとクライアントの双方向通信を行ってきました。とはいえ完全な解決策にはなり得ず、TCPの接続手続きを毎回やらなくてはいけない、同時接続数が増加してしまう、といった問題がありました。

 これらの問題を解決するために技術として登場したのがWebSocketです。これからWebSocketのサンプルとして簡単なチャットシステムを作成してみます。

 なお、9月21日にJava SE 9がリリースされました。本記事でも、今回からEarly Accessではなく、正式にリリースされたJava SE 9を使用していきます。

サーバーの実装

 HTTP/2 ClientでWebSocketのクライアントを作成する前に、サーバー側を実装しておきましょう。WebSocketをJava EEなどで使用するための仕様として、JSR 356 Java API for WebSocketがあります。TomcatやJettyなどの主だったServletコンテナがJSR 356に対応しています。本記事でも、JSR 356を使用します。

 なお、本記事はHTTP/2 Clientを主眼にしているため、JSR 356についての詳しい説明は省略します。

 チャットシステムのサーバー側のコードをリスト1に示しました。ここでは、クライアントからテキストメッセージを受け取ると、セッションを保持している他のクライアントにメッセージをそのまま送信するようにしています。

リスト1●チャットシステムのサーバー側の実装

@ServerEndpoint(value = "/simplechat")
public class SimpleChatServer {

    private static Set<Session> sessions = new CopyOnWriteArraySet<>();

    @OnOpen
    public void onOpen(Session session) {
        sessions.add(session);
    }
   
    @OnMessage
    public void onMessage(String message) {
        sessions.forEach(session -> session.getAsyncRemote().sendText(message));
    }
    
    @OnClose
    public void onClose(Session session) {
        sessions.remove(session);
    }
}

 WebSocketのURLスキーマはwsです。ここでは、ローカルの8084ポートでサーバーを起動させているので、URLはws://localhost:8084/simplechatになります。なお、TLSを使用する場合、URLスキーマはwssとなります。