C言語にてソケット関数を使って WebSocket クライアント を作成する
の続きです
前回はWebSocket クライアント を作成したので
今回はWebSocket サーバー を作成する。
まずはオープニングハンドシェイクから。
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Accept は
リクエストの Sec-WebSocket-Key の値(文字列)に
固定の文字列("258EAFA5-E914-47DA-95CA-C5AB0DC85B11") を連結したものの
SHA1ハッシュ値をBase64 エンコードしたもの
コードは下記のようになる。
void gen_accept_key(char* seckey) { const char GUID[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; size_t guid_len = strlen(GUID); size_t seckey_len = strlen(seckey); size_t buf_len = seckey_len + guid_len; char buf[buf_len+1]; memcpy(buf, seckey, seckey_len); memcpy(&buf[seckey_len], GUID, guid_len); unsigned char digest[SHA_DIGEST_LENGTH]; gen_sha1( (char *)buf, buf_len, (unsigned char *)digest); char* key = base64Encode( (char *)digest, SHA_DIGEST_LENGTH); strcpy(accept_key, key); free(key); }
C言語にて Openssl を使って SHA1 ハッシュを計算する
Sec-WebSocket-Key の値が
"dGhlIHNhbXBsZSBub25jZQ=="
のとき
Sec-WebSocket-Acceptの値は
"s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
となる。
Sec-WebSocket-Accept 以外は固定値でよい。
次は text(文字列) のエコーバック。
ペイロードは XOR 暗号化されているので 復号する。
XOR 暗号化と同じ処理を行うと復号さ れる。
コードは下記のようになる。
parse_payload(char* data, size_t data_size) { size_t payload_len = data[1] & PAYLOAD_LEN_MASK; char mask_bit = data[1] & B_MASK; char payload[payload_len]; if(mask_bit){ for(int i=0; i<payload_len; i++){ int j1 = FRAME_BASE_SIZE + FRAME_MASK_SIZE + i; int j2 = FRAME_BASE_SIZE + (i % 4); payload[i] = data[j1] ^ data[j2]; } } else { memcpy(payload, &data[FRAME_BASE_SIZE], payload_len); } }
クランアントから任意のタイミングで任意のメッサージが送られてくる。
ループ処理で待ち受けする。
コードは下記のようになる。
for(int i=0; i<LOOP; i++){ read_size = tcp_read( sockfd_client, read_data, DATA_SIZE); if(read_size >= 2){ char opcode = parse_frame(read_data, read_size); if(opcode == OP_TEXT){ proc_text(sockfd_client, read_data, read_size ); } else if(opcode == OP_CLOSE){ proc_close(sockfd_client, read_data, read_size ); } else if(opcode == OP_PING){ proc_ping(sockfd_client, read_data, read_size ); } } }
前回作ったクライアントから接続して動作確認する。
無事動いた。
Web Brawser から接続したとき JavaScript でクライアントを記述した html を返送する処理を追加する。
コード全文は Github に公開した
https://github.com/ohwada/MAC_cpp_Samples/tree/master/network/ws_server