LINEを始めとするメッセージアプリは、今や、私達の生活に欠かせないツールとなりました。
これらのメッセージアプリは、大規模なアクセスに対するリアルタイム通信、プッシュ通知、画像や動画の圧縮など、さまざま技術を複雑に組み合わせることで実現されています。
初心者が本格的なメッセージアプリをいきなり作ることは難しいため、この記事では、WebSocket を使ってリアルタイム通信を行なう、簡易的なチャットアプリを作る方法を解説します。
WebSocket
そもそも WebSocket とは、HTTP では実現が難しかったリアルタイムで同期的な通信をするために作られたプロトコルです。
リアルタイム通信におけるHTTPの問題点
HTTP は当初、HTMLで書かれた文書やファイルを転送するためのプロトコルとして生まれ、SNS やチャットのような、リアルタイム通信を必要とするアプリでの使用は想定されませんでした。
このような背景から、HTTP は 1つのコネクションにつき、1つのリクエストしか送ることができません。通信が必要になるたびにコネクションを作成する必要があり、通信はクライアント起点からしか発信できず、サーバー側からプッシュはできません。
また、HTTPプロトコルで取り決められたヘッダーや、ユーザーを識別するための Cookieなど 、本来やり取りしたいメッセージ以外にも多くのデータを一緒に送る必要があり、少量のデータを大量にやりとりするリアルタイム通信においては、一回のデータサイズが増えるのはデメリットでしかありません。
WebSocket の登場
そこで、リアルタイム通信における HTTP の問題を解決すべく、WebSocket が登場しました。
WebSocket は最初は HTML5 の仕様の一部として策定されましたが、現在では単独のプロトコルとして仕様が定められています。
サーバーからの通信も可能に
一度、クライアントから接続を行えば、以降はサーバーからの通信も行え、いわゆるプッシュ通知のようなことも、WebSocket であれば容易に実現ができるようになりました。
ヘッダーのデータ量が少ない
WebSocket はヘッダーのデータサイズが小さく、最も少なくて2バイト、最大で14バイトになっており、HTTP であれば、おおよそ 512バイト程度だったことを考えると、非常にコンバクトであることが分かります。
簡単なチャットアプリを作ろう
WebSocket の概要が分かったところで、WebSocket を使った簡単なチャットアプリを作ってみましょう。
サーバ側のソース
Java EE 7で新たに追加された、 Java API for WebSocket を使用すると、シンプルなコードでサーバ側のソースが実装できます。
今回は、クライアントか送信されたメッセージに「re: 」をつけて返すだけの簡単な処理を実装します。
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.OnError;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
/**
* WebSocketのサーバー側ソース
*/
@ServerEndpoint("/sample")
public class ServerEndPoint {
@OnOpen
public void onOpen(Session session) {
System.out.println("接続しました");
}
/**
* クライアントからメッセージを受信した時の処理
*/
@OnMessage
public String onMessage(String message) {
System.out.println("受信したメッセージ " + message);
return "re: \"" + message + "\".";
}
@OnError
public void onError(Throwable t) {
t.printStackTrace();
}
@OnClose
public void onClose(Session session) {
System.out.println("onClose");
}
}
クライアント側のソース
クライアント側のソースは HTML + JavaScirpt で構成します。
以下のサンプルコードでは、次のようなことをしています。
- ページ表示時にサーバーへ接続を行う
- 送信ボタンをクリックすると、メッセージをサーバーに送信する
- サーバーからメッセージを検知すると、メッセージをリストに表示
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>WebSocketチャットクライアント</title>
</head>
<body>
<div id="state" style="border: 1px solid #000; width: 10rem;"></div>
<div>
<input id="message" type="text" style="width: 20rem;">
<input id="send" type="button" value="送信"/>
</div>
<ul id="list"></ul>
<script type="text/javascript">
// Web Socketの生成
var webSocket = new WebSocket("ws://127.0.0.1/SampleServer/sample");
//接続成功時
webSocket.onopen = function () {
document.getElementById("state").innerText = "接続成功";
//サーバーからのメッセージを受信時した時の処理
webSocket.onmessage = function (event) {
var li = document.createElement("li");
li.innerText = event.data;
document.getElementById("list").appendChild(li);
}
};
//接続エラー時
webSocket.onerror = function() {
document.getElementById("state").innerText = "接続失敗";
};
//送信ボタンがクリックされた時の処理
document.getElementById("send").addEventListener("click", function() {
//サーバーにメッセージを送信
var inputElement = document.getElementById('message');
webSocket.send(inputElement.value);
inputElement.value = "";
});
</script>
</body>
</html>
これで、サーバーとクライアントの実装は完了です。
実行するには、まずサーバー側を Tomcat等で起動し、その後にクライアント側のHTMLをブラウザを立ち上げると、サーバーとの接続が行え、メッセージの送受信ができます。
まとめ
Java で簡単なチャットアプリを WebSocket 使って実装する方法を紹介してきました。
セキュリティや、大規模アクセスなどを考えると、もっと多くの仕組みが必要となりますが、まずは基本がおさえておきましょう。
【関連記事】
▶Javaソケット通信入門。TCPでデータの送受信をする
WebSocket 登場以前には、Cometというサーバーサイドでポーリングを行う手法を用いて、HTTPでリアルタイム通信を実現しているサービスもありましたが、HTTPのデメリット自体を解決できるわけではなく、ポーリングをすることにより、サーバー側に負荷がかかることから、根本的な解決には至りませんでした。