WebSockets は、TCP ストリーミング接続に依存するプロトコルです。WebSockets はメッセージベースのプロトコルですが。
独自のプロトコルを実装する場合は、最新の安定した仕様 (18/04/12) RFC 6455を使用することをお勧めします。この仕様には、ハンドシェイクとフレーミングに関するすべての必要な情報が含まれています。同様に、ブラウザ側およびサーバー側からの動作のシナリオに関するほとんどの説明。コードの実装中は、サーバー側に関する推奨事項に従うことを強くお勧めします。
簡単に言うと、WebSocket の操作を次のように説明します。
- サーバー ソケット(System.Net.Sockets) を作成し、それを特定のポートにバインドし、非同期で接続を受け入れてリッスンし続けます。そんな感じ:
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
serverSocket.Bind(新しい IPEndPoint(IPAddress.Any, 8080));
serverSocket.Listen(128);
serverSocket.BeginAccept(null, 0, OnAccept, null);
- ハンドシェイクを実装する受け入れ関数「OnAccept」が必要です。システムが毎秒膨大な量の接続を処理することを意図している場合、将来的には別のスレッドにある必要があります。
プライベート void OnAccept(IAsyncResult 結果) {
試す {
ソケット クライアント = null;
if (serverSocket != null && serverSocket.IsBound) {
クライアント = serverSocket.EndAccept(結果);
}
if (クライアント != null) {
/* ハンドシェイクと ClientSocket の管理 */
}
} catch(SocketException 例外) {
} 最後に {
if (serverSocket != null && serverSocket.IsBound) {
serverSocket.BeginAccept(null, 0, OnAccept, null);
}
}
}
- 接続が確立されたら、handshakeを行う必要があります。仕様1.3 Opening Handshakeに基づいて、接続が確立された後、いくつかの情報を含む基本的な HTTP 要求を受け取ります。例:
GET /チャット HTTP/1.1
ホスト: server.example.com
アップグレード: ウェブソケット
接続: アップグレード
Sec-WebSocket キー: dGhlIHNhbXBsZSBub25jZQ==
オリジン: http://example.com
Sec-WebSocket-Protocol: チャット、スーパーチャット
Sec-WebSocket-バージョン: 13
この例は、プロトコル 13 のバージョンに基づいています。古いバージョンにはいくつかの違いがありますが、ほとんどの最新バージョンは相互互換性があることに注意してください。ブラウザによっては、追加のデータが送信される場合があります。たとえば、ブラウザと OS の詳細、キャッシュなどです。
提供されたハンドシェイクの詳細に基づいて、回答行を生成する必要があります。それらはほとんど同じですが、提供された Sec-WebSocket-Key に基づく Accept-Key が含まれます。仕様 1.3 では、応答キーの生成方法が明確に説明されています。V13で使用している関数は次のとおりです。
static private string guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
プライベート文字列 AcceptKey(参照文字列キー) {
文字列 longKey = キー + GUID;
SHA1 sha1 = SHA1CryptoServiceProvider.Create();
byte[] hashBytes = sha1.ComputeHash(System.Text.Encoding.ASCII.GetBytes(longKey));
Convert.ToBase64String(hashBytes) を返します。
}
握手の答えは次のようになります。
HTTP/1.1 101 スイッチング プロトコル
アップグレード: ウェブソケット
接続: アップグレード
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
ただし、受け入れキーは、クライアントから提供されたキーと、以前に提供したメソッド AcceptKey に基づいて生成されたものでなければなりません。同様に、accept キーの最後の文字の後に、2 つの改行 "\r\n\r\n" を挿入してください。
ハンドシェイクの応答がサーバーから送信された後、クライアントは " onopen " 関数をトリガーする必要があります。つまり、後でメッセージを送信できます。
メッセージは未加工の形式で送信されませんが、データ フレーミングがあります。また、クライアントからサーバーへも、メッセージ ヘッダーで提供された 4 バイトに基づいてデータのマスキングを実装します。ただし、サーバーからクライアントへは、データにマスキングを適用する必要はありません。仕様のセクション5. データ フレーミングをお読みください。これが私自身の実装からのコピーアンドペーストです。これはすぐに使用できるコードではなく、変更する必要があります。WebSocket フレーミングを使用した読み取り/書き込みのアイデアと全体的なロジックを提供するために投稿しています。このリンクに移動します。
フレーミングを実装したら、ソケットを使用してデータを正しく受信していることを確認してください。たとえば、TCP はまだストリームベースのプロトコルであるため、一部のメッセージが 1 つにマージされるのを防ぐためです。つまり、特定のバイト数のみを読み取る必要があります。メッセージの長さは常にヘッダーに基づいており、ヘッダー自体に含まれるデータ長の詳細が提供されます。したがって、ソケットからデータを受信する場合、最初に 2 バイトを受信し、フレーミング仕様に基づいてヘッダーから詳細を取得します。次に、マスクが別の 4 バイトを提供する場合、データの長さに基づいて 1、4、または 8 バイトの長さになります。そして、データの後、それは自己です。読んだ後、マスキング解除を適用すると、メッセージ データを使用する準備が整います。
いくつかのData Protocolを使用したい場合があります。JSON を使用することをお勧めします。これは、トラフィックの経済性と、JavaScript のクライアント側で使いやすいためです。サーバー側では、いくつかのパーサーをチェックしたいかもしれません。それらはたくさんあります、グーグルは本当に役に立ちます。
独自の WebSockets プロトコルを実装すると、プロトコル自体を制御できるだけでなく、いくつかの利点と優れた経験が確実に得られます。ただし、これにはある程度の時間を費やす必要があり、実装の信頼性が高いことを確認する必要があります。
同時に、Google が (再び) 十分に備えている、すぐに使用できるソリューションを調べているかもしれません。