技術研究所の (あ) です。
HTTP でコネクションを張って双方向通信を行う WebSocket というのがありますよね。
技術研究所の作った、ブラウザで動いているとあるデモアプリがサーバとの通信に WebSocket を使っているのですが、そのデモの動きを改良したくなりました。
私はちょこちょことプロトタイピングするのによく Java を使うので、例によって Java アプリとして作ってみました。
そんなわけで、初めての WebSocket クライアント作成 (Java で) の簡単な記録です。
環境は、Windows 7 + Java 1.8.0_25 です。
まずは「きっと Java用の WebSocket ライブラリってあるよね」ということで検索してみます。
お、出てくる出てくる…と思ったら多くは
「Java で WebSocket を使ったサーバアプリを実装する」という話でしたorz。
まあ、クライアントはブラウザで JavaScript で動いたほうが便利な場合が多いですからね…。
検索ワードに「クライアント」を追加しても引っかかるのはほとんどそっちの話でしたが、埋もれかかってる中から何とか情報を引っ張りだしたところ
「Java EE に javax.websocket.* というのがあって(Java EE 7 以降)、それを使えばできる」
ということが判りました。
Java EE というのは Java SE の拡張機能セットのようなものですが、「仕様」として策定されているものなので「Java EE SDK」を Oracle 社のダウンロードページから入手すると、実際の中身は glassfish という Java EE 準拠のアプリケーションサーバです。
そんなわけで、入手した java_ee_sdk-7u2.zip を展開すると作られるフォルダ名が glassfish4 だったりするので、初心者にはなかなかの混乱ポイントとなりそうです。
で、しかも、今回使いたいクライアント側の実装は含まれていないようで (ひょっとしたらもっと探すとあるのかな…)、別途探してくる必要があります (多段トラップですね^^;)。
Tyrus Project ( https://tyrus.java.net/ ) というプロジェクトで参照実装を作っている、ということで、プロジェクトのウェブサイトのページから tyrus-standalone-client-1.9.jar をダウンロードしてきました (この記事を書いている時点ではバージョン 1.12 が最新のようです)。
ダウンロードした jar ファイルに CLASSPATH を通せば、WebSocket API を使ってクライアントプログラムが組めるはず、です。
WebSocket API を使うには、EndPoint クラスを継承する方法と、アノテーションを使う方法の二つがあるとのこと。見つけたサンプルがアノテーションを使っていたので、そっちを使ってみました。
import javax.websocket.*;
import java.net.*;
@ClientEndpoint
public class WebSocketTest
{
static boolean connected = false;
// - - - - - - -
@OnError
public void onError(Session session, Throwable cause) {
// エラー
System.out.println("error : " + session.getId() + ", " + cause.getMessage());
}
// - - - - - - -
@OnMessage
public void onMessage(String msg, Session session) {
// 文字列を受け取る
System.out.println("onMessage: " + msg);
}
// - - - - - - -
@OnClose
public void onClose(Session session, CloseReason closeReason) {
// 接続が閉じられた
System.out.println("closed");
connected = false;
}
// - - - - - - -
@OnOpen
public void onOpen(Session session) {
// 接続した
System.out.println("opened");
}
// - - - - - - -
public static void connect(String url) {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
Class<?> c = WebSocketForSignage.class;
// 接続
try (Session session = container.connectToServer(c, URI.create(url))) {
connected = true;
while (connected) {
// 接続中
// 文字列を送る
session.getBasicRemote().sendText("message");
(その他送信側の処理いろいろ)
}
} catch (Exception e) {
System.err.println(e);
}
}
}
このように、@ClientEndPoint をつけたクラスで、メッセージの受信は @OnMessage をつけたメソッドで、という感じで書くとクライアントのできあがり。簡単ですね。
あとはアプリケーションの目的に合わせてメッセージのやりとりなど捌けるようにすれば完成です。
以上、さらっと書きましたが、実際はいろいろ調べて試行錯誤を重ねつつの道のりでした。Java で WebSocket クライアントを書きたい、という需要は多くないのか(笑)、そこから出発するとあまりまとまった情報がみつからない、という印象です。
判ってしまえば、tyrus-standalone-client を使えばよいだけなのでとても簡単なんですけどねー。
ちらっと試しただけなので、上述の内容には間違いがあるかもしれませんし、まだまだ足りない部分も多いと思います。また何か解ったら適宜、補足・修正したいと思います。