3

これは私をかなりイライラさせ始めています。なぜなら、私が何をしようとも、パケットが一緒に押し込まれ、相手側でそれらを区別しなければならないのが煩わしいからです (オブジェクトは簡単ですが、可変文字列は面倒な場合があります)。これを回避する方法はありますか?

これは私が取り組んでいる大雑把なコードです(はい、初期化はここで行われます。これは大まかなテストコードなので、プログラミングの慣習が貧弱で申し訳ありません)

    sender.Connect("localhost", 8523);
    sender.Client.SendTimeout = 1000;
    sender.NoDelay = true;
    byte[] buffer = ASCIIEncoding.ASCII.GetBytes(message);
    sender.Client.Send(buffer);
    buffer = ASCIIEncoding.ASCII.GetBytes("DISCONNECT");
    sender.Client.Send(buffer);
    sender.Client.Close();

ご覧のとおり、2 つの送信が次々に発生し、ソケットはそれらを一緒に送信するのが最適であると判断します。それは素晴らしいことですが、私はそれを望んでいません。したがって、反対側では、それは

   helloDISCONNECT

この 2 つはブロック キューに自動的に読み込まれるため、別々に受信する必要があり、オブジェクトのサイズと文字列の解析を処理したくありません。

4

4 に答える 4

2

TCPは、バイトのストリームをレシーバーに提示します。

ストリームが閉じられるまで、TCPソケットの各読み取りは、1から指定したバッファーのサイズまでを返す可能性があります。それに応じてコーディングする必要があります。

TCPは、プログラムのメッセージフレーミングの概念を認識または認識していません。送信するための別々の呼び出しで3つの「メッセージ」を送信することは気にしません。有効なTCP実装は、ストリームから読み取る関数への呼び出しごとに1バイトを返すか、バイトを返す前に必要なだけバッファリングすることができます。それに応じてコーディングする必要があります。

TCPを介して送信するときにメッセージの観点から処理する場合は、独自のフレーミングを適用する必要があり、メッセージを読むときにそのフレーミングを自分で処理する必要があります。これは通常、既知のサイズの長さプレフィックスまたはメッセージターミネータのいずれかを意味します。

ここではこれについて詳しく説明します。コードはC++ですが、概念は引き続き適用されます。

于 2012-05-10T20:58:27.630 に答える
1

あなたが期待しているようです:

sender.NoDelay = true;

基本的に次のことを意味します。

sender.Client.Send(buffer);

...ビットがNICから外れるまで、ブロッキングコールになります。残念ながら、そうではありません。NoDelayネットワーク層に待機しないように指示するだけですが、実行している基になる呼び出しにはSend非同期動作があり、プログラムのスレッドは十分に速く実行されるため、基本的に2番目の文字列を追加する前にネットワーク層のスレッドがウェイクアップしません.

詳しくはNoDelay こちらをご覧ください。詳細については、そこにある注意事項をお読みください。

関連するいくつかの引用:

ストリーム Socket が Nagle アルゴリズムを使用しているかどうかを指定するブール値を取得または設定します。

Nagle アルゴリズムは、ソケットが小さなパケットをバッファリングし、特定の状況下でそれらを結合して 1 つのパケットに送信することにより、ネットワーク トラフィックを削減するように設計されています。

さらに、ビットを残すことを約束できたとしても、クライアント コードが 2 つの「パケット」があることを確認する前に、クライアントのネットワーク層がビットをバッファリングする可能性があります。

于 2012-05-10T17:41:32.970 に答える
1

に加えてsender.NoDelay = true、私にとって決定的に機能したトリックはsender.Client.Send(...)、 の形で後に追加の遅延を使用することでしたThread.Sleep(50)

実際の数は調査されておらず、たまたま最初から機能していました (50 ミリ秒は、送信キューにバックログを作成せずに待機するのに妥当な時間であると推定しました)。そのため、動作環境に合わせてこれをテストして調整してください。

余談: 私のデータを受信するアプリケーションは、各 TCP パケットが画面上の異なる行になるように、ビデオにテキストを重ねることができる CCTV レコーダーです。私は Nagle のアルゴリズムについて何かをすることを余儀なくされました。そうしないと、私の「行」が一緒に「まとまって」表示されました (マシンのバッファーの使用と明らかに関係がある追加のアーティファクトは言うまでもありません)。

于 2012-06-26T15:50:16.957 に答える
0

言及した制約を使用して TCP でメッセージを個別に受信することを確実にしたい場合は、各メッセージの後に接続をシャットダウンする必要があります。応答を期待しない場合は、読み取りと書き込みの両方をシャットダウンできます。応答が必要な場合は、書き込みのみをシャットダウンします。書き込みのためにシャットダウンを行うと、受信側は 0 バイトを受信することになり、受信側はメッセージの終わりを検出できます。たとえば、http は次のように機能します。

ここでのトレードオフは、メッセージごとに新しい TCP 接続を開く必要があるため、オーバーヘッドが発生することです。ただし、多くのアプリケーションでは、これは重要ではありません。

免責事項: これは、BSD ソケット API を使用して簡単に実装できます。私は C# の経験がほとんどなく、これらの低レベルのソケット操作を実行するための適切な API が提供されているかどうかわかりません。

于 2012-05-10T17:47:06.613 に答える