Boost.Beast で WebSocket を試す
の続きです。
前回は TCP通信のやり取りを解析したので、
今回はC言語のソケット関数を使ってクライアント を作成してみます。
すでにやっている人がいて どこかにコードがあると思ったが、見つからなかった。
下記のプロトコルの説明を参考にして、独自に実装した。
まずはオープニングハンドシェイクから。
GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Sec-WebSocket-Key は任意の文字列を Base64 エンコードしたもの。
コードは下記のようになる。
gen_ws_key(size_t size) { char rand[size+1]; for(int i=0; i<size; i++){ rand[i] = getRandomCharMix(); } char *b64 = base64Encode(rand, size); }
Sec-WebSocket-Key 以外は固定値でよい。
オープニングハンドシェイクは 昔書いたコードの応用でいける。
次は text(文字列) の送信。
ここはバイナリのフレーム形式なので、ちと面倒。
0バイト目: FIN ビット + OPコード
1バイト目: MASK ビット + ペイロード長
2バイト目から5バイト目: MASK バイト(4バイト)
6バイト目以降: ペイロード(文字列送信する文字列を XOR 暗号化したもの)
コードは下記のようになる。
build_frame_text(char* text) { data[0] = (unsigned char)(FIN | opcode) ; data[1] = (unsigned char)(MASK | text_len); for( int i=0; i<4; i++){ data[i+2] = mask[i]; } for( int i=0; i< text_len; i++){ data[i+6] = text[i] ^ mask[i % 4]; } }
前回試した Boost.Beast の WebSocket サーバーに接続して動作確認する。
無事 動いた。
ちょっとまごついたところ。
プロトコルの表記では FINビットは 0ビット目である。
コードでは 0x80 のように最上位ビット(7ビット目)を立てる。
TCP通信は上位ビットから送るビッグエンディアンである。
コード全文は Github に公開した
https://github.com/ohwada/MAC_cpp_Samples/tree/master/network/ws_client