[解決済み] Hello World" WebSocketのサンプルを作成する
質問
以下のコードが動作しない理由がわかりません。私はJavaScriptで私のサーバーコンソールアプリケーションに接続したい。そして、サーバーにデータを送信します。
以下はサーバーのコードです。
static void Main(string[] args)
{
TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 9998);
server.Start();
var client = server.AcceptTcpClient();
var stream = client.GetStream();
while (true)
{
var buffer = new byte[1024];
// wait for data to be received
var bytesRead = stream.Read(buffer, 0, buffer.Length);
var r = System.Text.Encoding.UTF8.GetString(buffer);
// write received data to the console
Console.WriteLine(r.Substring(0, bytesRead));
}
}
で、以下がそのJavaScriptです。
var ws = new WebSocket("ws://localhost:9998/service");
ws.onopen = function () {
ws.send("Hello World"); // I WANT TO SEND THIS MESSAGE TO THE SERVER!!!!!!!!
};
ws.onmessage = function (evt) {
var received_msg = evt.data;
alert("Message is received...");
};
ws.onclose = function () {
// websocket is closed.
alert("Connection is closed...");
};
このコードを実行すると、このようになります。
JavaScriptを実行すると、サーバーは接続を受け入れ、正常に確立されることに注意してください。しかし、JavaScriptはデータを送信することができません。送信メソッドを配置すると、接続が確立されているにもかかわらず、送信されません。どうしたらうまくいくでしょうか?
どうすれば解決しますか?
WebSocket は TCP ストリーム接続に依存するプロトコルです。WebSocketsはメッセージベースのプロトコルです。
もし、独自のプロトコルを実装したいのであれば、最新の安定した仕様(18/04/12版)を使用することをお勧めします。 RFC 6455 . この仕様には、ハンドシェイクとフレーミングに関するすべての必要な情報が含まれています。また、ブラウザ側とサーバ側での動作のシナリオに関する記述も多くあります。 サーバ側については、この勧告に従った実装をすることを強く推奨します。
WebSocketの使い方を一言で言うと、こんな感じです。
- サーバーソケットの作成 (System.Net.Sockets) を特定のポートにバインドし、非同期で接続を受け付け、リッスンし続ける。といったところでしょうか。
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP).Socket(System.Net.Socket)を作成します。 serverSocket.Bind(新しいIPEndPoint(IPAddress.Any, 8080))を実行します。 serverSocket.Listen(128)を実行します。 serverSocket.BeginAccept(null, 0, OnAccept, null);
- を用意する必要があります。 受理 関数 "OnAccept"でハンドシェイクを実装してください。将来的には、もしシステムが1秒間に大量の接続を処理することを意図しているならば、それは別のスレッドでなければなりません。
private void OnAccept(IAsyncResult result) { try { Socket client = null; if (serverSocket != null && serverSocket.IsBound){。 client = serverSocket.EndAccept(result)。 } if (client != null) { /* ハンドシェイクとクライアント管理 /* ClientSocketのハンドシェイクと管理 */ } } catch(SocketExceptionの例外) { } final { } catch(SocketExceptionの例外) } finally { if (serverSocket != null && serverSocket.IsBound){。 serverSocket.BeginAccept(null, 0, OnAccept, null); } } }
- 接続が確立したら ハンドシェイク . 仕様に基づき 1.3 オープニングハンドシェイク に基づいて、接続が確立されると、いくつかの情報を含む基本的な HTTP リクエストを受け取ります。例
GET /chat HTTP/1.1 ホスト:server.example.com アップグレード:ウェブソケット 接続 アップグレード Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== オリジン: http://example.com Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13
この例は、プロトコル 13 のバージョンに基づいています。古いバージョンではいくつかの違いがありますが、ほとんどの最新バージョンは相互互換性があることに留意してください。ブラウザによっては、いくつかの追加データを送信することがあります。たとえば、ブラウザーと OS の詳細、キャッシュ、その他です。
これらはほとんど同じですが、提供された Sec-WebSocket-Key に基づいた Accept-Key が含まれます。仕様書1.3では、レスポンスキーを生成する方法が明確に記述されています。 以下は、私がV13で使っていた関数です。
static private string guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; プライベート文字列AcceptKey(ref文字列key){(ref文字列guid) 文字列 longKey = key + guid; SHA1 sha1 = SHA1CryptoServiceProvider.Create(); byte[] hashBytes = sha1.ComputeHash(System.Text.Encoding.ASCII.GetBytes(longKey)).Byte[] hashBytes = sha1.ComputeHash(System.Text.Encoding.ASCII.GetBytes(longKey)); return Convert.ToBase64String(hashBytes); }
握手会の答えはこんな感じです。
HTTP/1.1 101 プロトコルの切り替え アップグレード:ウェブソケット 接続する アップグレード Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
ただし、acceptキーは、クライアントから提供されたキーと、私が前に提供したAcceptKeyメソッドに基づいて生成されたものである必要があります。また、accept keyの最後の文字の後に、" \rnrn" と2行入れてください。
-
サーバーからハンドシェイクアンサーが送信された後、クライアントは"をトリガーする必要があります。 onopen 関数を呼び出す必要があります。
-
メッセージは生のまま送信されませんが、メッセージには データ・フレーミング . そして、クライアントからサーバへも、メッセージヘッダの4バイトを元にデータのマスキングを実装します。ただし、サーバからクライアントへはデータに対するマスキングは必要ありません。セクションを読む 5. データフレーミング を読んでください。 以下は、私自身の実装からのコピーペーストです。すぐに使えるコードではないので、修正が必要ですが、WebSocketフレームを使った読み書きの全体的なロジックを理解するために掲載しています。次のページに移動します。 このリンク .
-
フレーミングを実装した後は、ソケットを使って正しい方法でデータを受信できるようにします。例えば、TCPはまだストリームベースのプロトコルなので、いくつかのメッセージが1つに統合されるのを防ぐためです。これは、特定のバイト数だけ読まなければならないことを意味します。メッセージの長さは、常にヘッダとそれ自身のヘッダで提供されるデータの長さの詳細に基づいています。つまり、ソケットからデータを受信する場合、まず2バイトを受信し、フレーミング仕様に基づいてヘッダーから詳細を取得し、マスクが提供された場合はさらに4バイト、そしてデータの長さに基づいて1、4または8バイトであるかもしれません。そして、データの後に自己のデータ。読み込んだら、デマスキングを適用すれば、メッセージデータは使えるようになります。
-
を使いたいかもしれませんが、いくつかの データプロトコル がありますが、クライアント側でJavaScriptを使う場合はトラフィックの観点からJSONを使うことをお勧めします。サーバーサイドでは、いくつかのパーサーをチェックしたいかもしれません。それらの多くは、Googleは本当に役に立つことができます。
独自のWebSocketプロトコルを実装することは、間違いなくいくつかの利点と、プロトコルそれ自体の制御と同様に得られる素晴らしい経験を持っています。しかし、あなたはそれを行うにはいくつかの時間を費やし、その実装が高い信頼性を持つことを確認する必要があります。
同時に、あなたは、Googleが(再び)十分に持っているすぐに使用できるソリューションを見ることができるかもしれません。
関連
-
[解決済み】指定されたキャストが有効でない?
-
[解決済み】Excel "外部テーブルが期待された形式ではありません。"
-
[解決済み】「入力文字列が正しい形式ではありませんでした」エラーの解決方法は?[重複しています]。
-
[解決済み】非静的メソッドはターゲットを必要とする
-
[解決済み】画像のペイントにTextureBrushを使用する方法
-
[解決済み】ファイルやアセンブリ、またはその依存関係の1つをロードできませんでした。
-
[解決済み】Microsoft.Extensions.LoggingからILoggerを解決することができない
-
[解決済み] JavaScriptで複数行の文字列を作成する
-
[解決済み] ループ内のJavaScriptクロージャ - シンプルな実用例
-
[解決済み] ストリームからのバイト配列の作成
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】プログラム実行中に1秒待つ
-
[解決済み】C#はJavaのcharAt()と同等?)
-
[解決済み】プロジェクトビルド時のエラー。エディタでスクリプトにコンパイルエラーがあるため、Playerのビルドにエラーが発生する
-
[解決済み] EntityTypeにキーが定義されていないエラー
-
[解決済み】OnCollisionEnter2Dが実行されない?
-
[解決済み】5.7.57 SMTP - MAIL FROMエラー時に匿名メールを送信するためにクライアントが認証されない
-
[解決済み】2つ(またはそれ以上)のリストを1つに統合する(C# .NETで
-
[解決済み] 2つのリストを結合する
-
[解決済み】パラメータ付きRedirectToAction
-
[解決済み】ファイルやアセンブリ、またはその依存関係の1つをロードできませんでした。