背景
過去記事:https://qiita.com/take4eng/items/d0b009c48ee8c3fe420a
上記の過去記事に記述しているように、Javaでサーバープログラムを作成しソケット通信を実施。
⇒ HTTP通信をゴリ押しで解析しているため、無駄に複雑なコードになっている。
Java EEにはsocket通信に関するAPIが多数存在し、非常に簡単に実装することが可能。
既に多くの人がまとめてくれてはいるが、実装した内容をまとめておく。
便利なAPIが用意されているのにゴリ押しで解析なんて誰もやらないよね
そりゃググってもなかなか出てこないわ…
実践内容
- WebSocket API の使用方法
- APIを使用したサーバープログラムを作成
- 過去記事内のクライアントプログラムコードを編集しチャットアプリ作成
WebSocket API の使用方法
基本的なWebSocket APIについて説明する。
ここで紹介するもの以外にも多数のAPIが存在するが、必要ならググると良い。
Endpointクラスの作成
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/コンテキストパス")
public class SanpleEndpoint {
}
- ServerEndpointクラスをインポート
- クラスにアノテーション@ServerEndpointを付与
- ファイルの場所を示すコンテキストパスを記述
処理メソッドの作成
/*
各クラスをインポートしておく
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
*/
//クライアントと接続したときの処理
@OnOpen
public void onOpen(Session session) {
}
//クライアントからメッセージを受け取ったときの処理
@OnMessage
public void onMessage(String message) {
}
//エラーが発生したときの処理
@OnError
public void onError(Throwable error) {
}
//クライアントと接続が切れたときの処理
@OnClose
public void onClose(Session session) {
}
- 必要なクラスをインポート
- メソッドに対応した各アノテーションを付与
- 引数は必要に応じて変更 , 追加可能
APIを使用したサーバープログラムを作成
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
// Webソケットのサーバ側クラスであること表すアノテーション。
// 引数(wSck)はクライアントから接続時、使われるURIを表す。
@ServerEndpoint(value = "/wSck")
public class SocketFree2 {
//クライアントのセッションスレッドを作成(クライアント毎にそれぞれのセッションを保存)
//Set:重複要素のないコレクション
//CopyOnWriteArrayList:java.util.Setをスレッドセーフにしたもの
private static Set<Session> user = new CopyOnWriteArraySet<>();
@OnOpen//クライアントと接続したとき
public void onOpen(Session mySession) {
System.out.println("connect ID:"+mySession.getId());//session.getId():セッションIDを取得
user.add(mySession);//クライアント毎のセッションをリストに追加
}
@OnMessage//クライアントからデータが送信されたとき
public void onMessage(String text , Session mySession) {//引数は送信されたテキストと送信元のセッション
System.out.println(text);
//getAsyncRemote():RemoteEndpointのインスタンスを取得
//sendText(String):クライアントにテキストを送信
for (Session user : user) {
user.getAsyncRemote().sendText(text);
System.out.println(user.getId()+"番目に"+mySession.getId()+"番目のメッセージを送りました!");
}
if(text.equals("bye")) onClose(mySession);//textが「bye」なら切断する
}
@OnClose//クライアントが切断したとき
public void onClose(Session mySession) {
System.out.println("disconnect ID:"+mySession.getId());
user.remove(mySession);//切断したクライアントのセッションをリストから削除
try {
mySession.close();//closeメソッドで切断
} catch (IOException e) {
System.err.println("エラーが発生しました: " + e);
}
}
}
コードの解説
1.クラスにEndpointアノテーション@ServerEndpointを付与し、コンテキストパスを記述
@ServerEndpoint(value = "/wSck")
2.各クライアントを識別するリストを作成
private static Set<Session> user = new CopyOnWriteArraySet<>();
3.onOpenメソッド:クライアントのセッションをリストに追加
user.add(mySession);
4.onMessageメソッド:受信したテキストをそのままクライアントへ送信
⇒ for文で接続しているクライアント全員に送信する
user.getAsyncRemote().sendText(text);
5.onCloseメソッド:接続が切れたクライアントを削除
5-1.userリストから削除:user.remove(mySession);
5-2.セッションを削除し接続を切る:mySession.close();
実行結果
クライアントプログラムのアドレスを変更し、webブラウザで実行。
※コード内容は過去記事を参照
var wSck= new WebSocket("ws://localhost:8080/プロジェクト名/コンテキストパス");
(今回なら"ws://localhost:8080/freeWeb2/wSck"
)
送信した内容が表示されるチャットアプリが完成。
複数のブラウザからのアクセスにも対応している。
感想
APIを使用することで非常に簡単にソケット通信を行うことができた。
過去記事で記述しのものと比べるとコードの記述量は約1/4。すごい。超簡単。
他にもエンコード、デコード処理やjsonデータの扱いについても簡単にできるらしい。
今回は使用していないが、本格的な開発をするなら必要になるだろう。
詳細は参考ページを参照。