WebSocket とは
- クライアントとリモートホストの間で双方向通信を可能とするプロトコル。
- セキュリティモデルはウェブブラウザでよく用いられるオリジンをベースとしたモデル。
XMLHttpRequest
やロングポーリングに頼らずにサーバとの双方向通信を必要とするブラウザアプリケーションのためのメカニズムを提供する。- クライアント・サーバ間の双方向のトラフィックのためにTCPコネクションを一つだけ張る。
プロトコルの概要
プロトコルはハンドシェイクとデータ転送の2つの部分からなる。
ハンドシェイク
クライアント -> サーバ
GET/chatHTTP/1.1Host:server.example.comUpgrade:websocketConnection:UpgradeSec-WebSocket-Key:dGhlIHNhbXBsZSBub25jZQ==Origin:http://example.comSec-WebSocket-Protocol:chat, superchatSec-WebSocket-Version:13
サーバ -> クライアント
HTTP/1.1101Switching ProtocolsUpgrade:websocketConnection:UpgradeSec-WebSocket-Accept:s3pPLMBiTxaQ9kYGzzhZRbK+xOo=Sec-WebSocket-Protocol:chat
ハンドシェイクが成功すると、クライアントとサーバは1つ以上のフレームからなるメッセージをお互いに送出し合うことになる。
Node.js でシンプルな WebSocket 通信
Node.js では、wsというWebSocketライブラリを用いてシンプルな WebSocket 通信ができる(Socket.IOでも可能)。
サーバ側のコード
constWebSocket=require('ws')constserver=newWebSocket.Server({port:3000})server.on('connection',ws=>{ws.send('connected!')ws.on('message',message=>{console.log('received: %s',message)})})
クライアント側のコード
constws=require('ws')constclient=newws('ws://localhost:3000')client.on('open',()=>{client.send('hello')})client.on('message',message=>{console.log(message)})
node server.js
でWebSocketサーバを立ち上げた後 node client.js
を実行すると、サーバ側では
received: hello
と出力され、クライアント側では
connected!
と出力される。
WebSocket でチャットアプリを作る
blessedというクールな CUI を作れるライブラリを使って、超シンプルなチャットアプリ(もどき)を作ってみる。
サーバ側
constWebSocket=require('ws')constserver=newWebSocket.Server({port:3000})constsockets=newMap()constbroadcast=message=>{console.log(message)server.clients.forEach(client=>{if(client.readyState===WebSocket.OPEN){client.send(message)}})}server.on('connection',socket=>{socket.on('message',message=>{if(sockets.has(socket)){constname=sockets.get(socket)broadcast(`${name}: ${message}`)}else{sockets.set(socket,message)broadcast(`${message} entered the room.`)}})socket.on('close',()=>{constname=sockets.get(socket)if(name){sockets.delete(socket)broadcast(`${name} left the room.`)}})})
クライアント側
constws=require('ws')constblessed=require('blessed')constscreen=blessed.screen({smartCSR:true})screen.title='chat'constchatList=blessed.list({border:{type:'line'}})consttextbox=blessed.textbox({height:'10%',bottom:0,input:true,inputOnFocus:true,border:{type:'line'}})constclient=newws('ws://localhost:3000')client.on('open',async()=>{textbox.setText('(Please enter your name)')textbox.focus()screen.render()})client.on('message',message=>{chatList.insertLine(0,message)screen.render()})textbox.key(['enter'],()=>{client.send(textbox.getText())textbox.clearValue()chatList.render()textbox.focus()})constEXIT_COMMANDS=['escape','C-c']constexit=()=>process.exit(0)screen.key(EXIT_COMMANDS,exit)chatList.key(EXIT_COMMANDS,exit)textbox.key(EXIT_COMMANDS,exit)screen.append(chatList)screen.append(textbox)screen.render()
実際の動作
それっぽくは動く。
所感
- blessed の API がよくわからない
- ブラウザを UI としたチャットアプリを作ってみたい
- 随時更新する