SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事(AD)

「WebSphere Application Server Liberty Core」で新たに正式サポートされたWebSocketを使ってみた

  • このエントリーをはてなブックマークに追加

6. WebSocketを使った一対多の通信

 HelloEndpointのサンプルは、サーバーとクライアントの一対一の通信の例だった。そこで今度は、1つのサーバーに対して複数のクライアントが接続して一対多の通信をするチャットアプリケーションをWebSocketを使って作ってみよう。すなわち、サーバー側のエンドポイントは複数のクライアントからの接続を同時に受け付け、クライアントからメッセージを受け取った場合にはそれを接続中のすべてのクライアントに対して転送する。

 まず、送信側となるクライアントのJavaScriptを考えよう。せっかくならば発言したユーザ名などの情報も送りたいので、メッセージ送信にはJSONを利用してみる。WebSocketではバイナリデータを送ることも可能だが、単純なメッセージであればJSONで事足りるだろう。今回は次のようなJSONデータを使うことにする。type属性でメッセージの種類を指定し、data属性でメッセージデータを格納したオブジェクトを渡す。メッセージデータ部分のname属性はユーザ名を、text属性はテキストメッセージを表す。

リスト6.1 メッセージ通信用のJSONフォーマット
■クライアント→サーバー

ログイン時: { type:login, data:{ name:xxx } }
ログアウト時: { type:logout, data:{ name:xxx } }
メッセージ送信時: { type:message, data:{ name:xxx, text:xxx } }


■サーバー→クライアント

メッセージ送信時: { type:message, data:{ text:xxx } }

 接続がオープンしたときには、次のようにしてログインメッセージを送信する。

リスト6.2 ログイン時のJSONデータの送信
webSocket.onopen = function(event) {
    var name = document.getElementById("name").value; // ユーザ名
    var message = {
        type: "login",
        data: { name: name }
    };
    webSocket.send(window.JSON.stringify(message));
}

 接続をクローズするときには、次のようにログアウトメッセージを送信してからclose()メソッドを呼び出す。

リスト6.3 ログアウト時のJSONデータの送信
if (webSocket.readyState == webSocket.OPEN) {
    var name = document.getElementById("name").value; // ユーザ名
    var message = {
        type: "logout",
        data: { name: name }
    };
    webSocket.send(window.JSON.stringify(message));
    webSocket.close();
}

 そしてテキストメッセージを投稿するときには、ユーザ名とメッセージの内容を送信する。送信するメッセージの内容がJSON形式になっただけで、基本的にはテキストメッセージを送る方法と違いはない。

リスト6.4 メッセージを載せたJSONデータの送信
if (webSocket.readyState == webSocket.OPEN) {
    var name = document.getElementById("name").value;                 // ユーザ名
    var inputmessage = document.getElementById('inputmessage').value; // メッセージ
    var message = {
        type: "message",
        data: { name: name, text: inputmessage }
    };
    webSocket.send(window.JSON.stringify(message));
    document.getElementById('inputmessage').value = "";
}

 サーバーから送られてくるメッセージもJSON形式なので、そこからメッセージテキスト部分を取り出して画面のコンテンツに追加する。

リスト6.5 サーバーから送られたJSONデータの受信
webSocket.onmessage = function(event) {
    var receive = JSON.parse(event.data);
    var message = receive.data.text;
    var msgBox = document.getElementById("message");
    var currentText = msgBox.innerHTML;
    msgBox.innerHTML = "<div>" + message + "</div>" + currentText;
}

 さて、サーバー側では受け取ったJSON形式のデータを解析して、type属性の値に応じて処理を変えなければならない。JavaプログラムでJSONデータを扱うために、今回はLibertyプロファイルに付属するJSONライブラリ(com.ibm.json.javaパッケージ)を利用する。このライブラリは「com.ibm.websphere.appserver.api.json_1.0.1.jar」というファイルに納められている。プロジェクトのプロパティ設定で、ビルド・パスに「WebSphere Application Server Liberty Profile」を追加しておけば使うことができる。もちろん、この部分はJSR 353として標準化されている「Java API for JSON Processing(javax.json)」を使うように置き換えてもよい。

図6.6
図6.6

 com.ibm.json.javaでは、JSONデータをJSONObjectというクラスとして定義している。このクラスはMapクラスを継承している。従って、基本的なデータの出し入れはMapクラスと同じ方法でできると考えてよい。JSON形式のテキストデータからJSONObjectオブジェクトに変換するには、JSONObject.parse()メソッドを使用する。次の例は、受け取ったJSONデータから各属性の値を取り出し、type属性に応じてそれぞれ異なるメッセージをクライアントに送信する例である。メッセージの送信は後述するsendMessage()メソッドで行う。

リスト6.7 クライアントからのメッセージの受信
@OnMessage
public void receiveMessage(String msg, Session session) throws IOException {
    JSONObject json = JSONObject.parse(msg);
    String type = (String)json.get("type");
    JSONObject data = (JSONObject)json.get("data");
    String name = (String)data.get("name");
    switch (type) {
        case "login":
            sendMessage(name + "さんが入室しました。", session);
            break;
        case "logout":
            sendMessage(name + "さんが退室しました。", session);
            break;
        case "message":
            String text = (String)data.get("text");
            sendMessage(name + ": " + text, session);
            break;
        default:
            break;
    }
}

 接続が確立しているすべてのセッションに同時にメッセージを送信するには、それらのセッションの情報を知る必要がある。この情報は、1つのSessionオブジェクトから簡単に取得できるようになっている。従ってメッセージを受け取った際には、その送信元となったSessionオブジェクトを取得し、そこから他のセッションのリストを取り出してそれぞれに対して受け取った内容を転送すればいいわけだ。具体的には、次のようにgetOpenSessions()メソッドを呼び出してSessionオブジェクトが格納されたSetオブジェクトを取得し、それぞれにsendText()メソッドを実行するようなコードになる。

リスト6.8 メッセージの一斉送信
private void sendMessage(String msg, Session currentSession) {
    // 返すメッセージのJSON形式
    // { type:message, data:{ message: xxxx } }
    JSONObject data = new JSONObject();
    data.put("text", msg);
    JSONObject response = new JSONObject();
    response.put("type", "message");
    response.put("data", data);
    System.out.println("送信: " + response.toString());

    Set<Session> sessions = currentSession.getOpenSessions();
    for(Session session: sessions) {
        try {
            session.getBasicRemote().sendText(response.serialize());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 以上のことを踏まえて、チャットアプリケーションを実現するクライアント側とサーバー側のプログラムは、添付サンプルコードの「chat.html」および「ChatEndpoint.java」のようになった。

 このプロジェクトを実行してWebブラウザからアクセスすると、最初に図6.9のように表示される。名前を入力して[入室]ボタンを押せば、WebSocketによる通信が開始されて、図6.10のようにサーバーから受け取ったメッセージが表示される。複数のWebブラウザで同時に接続すれば、図6.11のようにチャットを楽しむことができる。

図6.9
図6.9
図6.10
図6.10
図6.11
図6.11

次のページ
7. jQueryと組み合わせる

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

杉山 貴章(スギヤマ タカアキ)

有限会社オングスにて、Javaを中心としたソフトウェア開発や、プログラミング関連書籍の執筆、IT系の解説記事やニュース記事の執筆などを手がけている。そのかたわら、専門学校の非常勤講師としてプログラミングやソフトウェア開発の基礎などを教えている。著書に『Javaアルゴリズム+データ構造完全制覇』『Ja...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

【AD】本記事の内容は記事掲載開始時点のものです 企画・制作 株式会社翔泳社

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/8418 2015/02/27 19:04

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング