WebSocket (Version8, hybi-10) のプロトコルとか
WebSocketを使ってみた時のメモ
■ WebSocketとは
ウェブサーバーとブラウザの双方向通信のための規格です。
例えば、従来のチャットサイトだと、相手が発言したとしても、リアルタイムでメッセージが更新されるわけではなく、メッセージを見るためには、ページを更新する必要があります。
ブラウザ → サーバー → ブラウザ
このような一連のやり取りによって、内容を更新するため、ブラウザから更新を要求する必要があります。
WebSocketの技術を使うことで、一旦WebSocket接続をしてしまえば、
サーバー → ブラウザ
というようにサーバーからブラウザに向けてデータを送信できるため、リアルタイムでブラウザにメッセージを表示させることができます。
■ WebSocketのバージョン
WebSocketは、登場して2年程度しか経っていないため、これまで何度も改訂がされてきました。
プロトコルの仕様が変わっていて、それぞれのプロトコルに互換性が無かったりするので、
サーバーとブラウザでそれぞれ互換性が無いと通信することができません。
よって、サーバーが古いバージョンのまま更新されないと、新しいブラウザでは動作しないので注意が必要です。
例えば、Firefox 7やChrome 14 ではWebSocketのバージョンは8(ドラフトhybi-10)です。
(WebSocketのバージョンとドラフトのバージョンが違う場合があります…)
■ サーバー・クライアントの種類と対応状況
有名どころは、Wikipediaにまとめてあります
Wikipedia - WebSocket
stackoverflowのこのページも参考になると思います
What browsers support the WebSocket API?
■ WebSocketプロトコル
まず、WebSocketプロトコルの仕様は、IETFのサイトで確認できます
The WebSocket protocol
WebSocket APIの仕様は、W3Cのサイトにあります
The WebSocket API
以下の画像は、Firefox 7 でWebSocketサーバーに接続して、メッセージを送受信してクローズするまでのプロトコルです。

これをバイト列で表すと、このようになります。

赤文字の部分は、ブラウザからサーバーへの通信、青文字はサーバーからブラウザです
◆ ハンドシェイク
クライアント、サーバー間のウェブソケットを確立するためのやり取り
Note: 以下は、WebSocketバージョン8 (draft-ietf-hybi-thewebsocketprotocol-10で規定)
のプロトコルで、古いバージョンのプロトコルと異なります。
◇ ハンドシェイクリクエスト (ブラウザ → サーバー)
不要な部分を削除すると、
◇ ハンドシェイクレスポンス (サーバー → ブラウザ)
上のハンドシェイク要求を受け取ると、サーバーは下の応答を返します。
サーバーは、リクエストがウェブソケットのハンドシェイク要求であり、かつ対応しているバージョンである場合に上のような応答を返します。サーバーとブラウザ間でWebSocket接続が確立され、データのやり取りができるようになります。
リクエストが不正などの場合は、HTTP/1.1 400 Bad Request などの応答が返され、WebSocketの接続に失敗します。
Sec-WebSocket-Acceptヘッダの "HLsuiHpqiMRADWIpBmfKuNWkpHk=" という文字列は、このように作られます:
リクエストのSec-WebSocket-Key: WIY4slX50bnnSF1GaedKhg==の
"WIY4slX50bnnSF1GaedKhg=="という文字列に、
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"という文字列を連結して
"WIY4slX50bnnSF1GaedKhg==258EAFA5-E914-47DA-95CA-C5AB0DC85B11"とします。
Note: 接続の度にSec-WebSocket-Keyの値は異なりますが、連結する"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"という文字列は変わりません。
連結してできた文字列をSHA-1でハッシュをとります。
得られた20バイトのバイト列を、base64でエンコードすることによって、Sec-WebSocket-Acceptヘッダの値が求まります。
プログラムではこんな感じです:
これでWebSocketを用いてやり取りができるようになりました!
長くなったので続きは後日、別の記事で書くかもしれません。
■ WebSocketとは
ウェブサーバーとブラウザの双方向通信のための規格です。
例えば、従来のチャットサイトだと、相手が発言したとしても、リアルタイムでメッセージが更新されるわけではなく、メッセージを見るためには、ページを更新する必要があります。
ブラウザ → サーバー → ブラウザ
このような一連のやり取りによって、内容を更新するため、ブラウザから更新を要求する必要があります。
WebSocketの技術を使うことで、一旦WebSocket接続をしてしまえば、
サーバー → ブラウザ
というようにサーバーからブラウザに向けてデータを送信できるため、リアルタイムでブラウザにメッセージを表示させることができます。
■ WebSocketのバージョン
WebSocketは、登場して2年程度しか経っていないため、これまで何度も改訂がされてきました。
プロトコルの仕様が変わっていて、それぞれのプロトコルに互換性が無かったりするので、
サーバーとブラウザでそれぞれ互換性が無いと通信することができません。
よって、サーバーが古いバージョンのまま更新されないと、新しいブラウザでは動作しないので注意が必要です。
例えば、Firefox 7やChrome 14 ではWebSocketのバージョンは8(ドラフトhybi-10)です。
(WebSocketのバージョンとドラフトのバージョンが違う場合があります…)
■ サーバー・クライアントの種類と対応状況
有名どころは、Wikipediaにまとめてあります
Wikipedia - WebSocket
stackoverflowのこのページも参考になると思います
What browsers support the WebSocket API?
■ WebSocketプロトコル
まず、WebSocketプロトコルの仕様は、IETFのサイトで確認できます
The WebSocket protocol
WebSocket APIの仕様は、W3Cのサイトにあります
The WebSocket API
以下の画像は、Firefox 7 でWebSocketサーバーに接続して、メッセージを送受信してクローズするまでのプロトコルです。

これをバイト列で表すと、このようになります。

赤文字の部分は、ブラウザからサーバーへの通信、青文字はサーバーからブラウザです
◆ ハンドシェイク
クライアント、サーバー間のウェブソケットを確立するためのやり取り
Note: 以下は、WebSocketバージョン8 (draft-ietf-hybi-thewebsocketprotocol-10で規定)
のプロトコルで、古いバージョンのプロトコルと異なります。
◇ ハンドシェイクリクエスト (ブラウザ → サーバー)
GET /chat HTTP/1.1
Host: 192.168.11.3:58787
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:7.0.1) Gecko/20100101 Firefox/7.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ja,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7
Connection: keep-alive, Upgrade
Sec-WebSocket-Version: 8
Sec-WebSocket-Origin: null
Sec-WebSocket-Extensions: deflate-stream
Sec-WebSocket-Key: WIY4slX50bnnSF1GaedKhg==
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
不要な部分を削除すると、
GET /chat HTTP/1.1
Host: 192.168.11.3:58787
Connection: keep-alive, Upgrade
Sec-WebSocket-Version: 8
Sec-WebSocket-Origin: null
Sec-WebSocket-Extensions: deflate-stream
Sec-WebSocket-Key: WIY4slX50bnnSF1GaedKhg==
Upgrade: websocket
◇ ハンドシェイクレスポンス (サーバー → ブラウザ)
上のハンドシェイク要求を受け取ると、サーバーは下の応答を返します。
HTTP/1.1 101 Switching Protocols
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Accept: HLsuiHpqiMRADWIpBmfKuNWkpHk=
サーバーは、リクエストがウェブソケットのハンドシェイク要求であり、かつ対応しているバージョンである場合に上のような応答を返します。サーバーとブラウザ間でWebSocket接続が確立され、データのやり取りができるようになります。
リクエストが不正などの場合は、HTTP/1.1 400 Bad Request などの応答が返され、WebSocketの接続に失敗します。
Sec-WebSocket-Acceptヘッダの "HLsuiHpqiMRADWIpBmfKuNWkpHk=" という文字列は、このように作られます:
リクエストのSec-WebSocket-Key: WIY4slX50bnnSF1GaedKhg==の
"WIY4slX50bnnSF1GaedKhg=="という文字列に、
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"という文字列を連結して
"WIY4slX50bnnSF1GaedKhg==258EAFA5-E914-47DA-95CA-C5AB0DC85B11"とします。
Note: 接続の度にSec-WebSocket-Keyの値は異なりますが、連結する"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"という文字列は変わりません。
連結してできた文字列をSHA-1でハッシュをとります。
得られた20バイトのバイト列を、base64でエンコードすることによって、Sec-WebSocket-Acceptヘッダの値が求まります。
プログラムではこんな感じです:
MAGIC = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
s = Sec-WebSocket-Keyの値;
Sec-WebSocket-Acceptの値 = base64encode( sha1( s + MAGIC ) );
これでWebSocketを用いてやり取りができるようになりました!
長くなったので続きは後日、別の記事で書くかもしれません。
スポンサーサイト