3

私はおそらく素朴な質問をしています。私は周りを見回しましたが、それに対処する直接的な答えを見たことがなく、ここで簡単な答えが得られるかもしれないと考えました. bsd ソケットを使用する単純な TCP/IP クライアント/サーバー選択ループで、クライアントがサーバーに同時に到着する 2 つのメッセージを送信する場合、サーバーで recv を 1 回呼び出すと、両方のメッセージがバッファーにバンドルされて返されるか、recv がそれぞれを強制します。別個の到着メッセージを個別に読む必要がありますか?

クライアントが送信するメッセージをどのように作成しているかがわからない環境で作業しているため、質問します。通常、recv は 12 バイトが読み取られ、次に 915、次に 12 バイト、次に 915 というように 12 から 915 のパターンが交互に繰り返されることを報告しますが、927 (915+12) を報告することもあります。クライアントがサーバーに送信する前に情報の一部をまとめているか、recv が呼び出される前にメッセージが到着し、recv が保留中のすべてのバイトを同時にプルすると考えていました。そのため、recv の動作を正しく理解していることを確認したかったのです。おそらく、ここで私の理解に何かが欠けていると思います。誰かがそれを指摘してくれることを願っています、ありがとう!

4

3 に答える 3

7

TCP/IP はストリーム ベースのトランスポートであり、データグラム ベースのトランスポートではありません。ストリームでは、 と の間に 1 対 1 の相関関係はありませsend()recv()。これは、データグラムにのみ当てはまります。したがって、複数の可能性を処理できるように準備する必要があります。

  1. への 1 回の呼び出しがsend()1 つの TCP パケットに収まり、 への 1 回の呼び出しで完全に読み取られる場合がありますrecv()

  2. への 1 回の呼び出しsend()が複数の TCP パケットにまたがる場合があり、recv()すべてを読み取るには を複数回呼び出す必要があります。

  3. への複数回の呼び出しがsend()1 つの TCP パケットに収まり、 への 1 回の呼び出しで完全に読み取られる場合がありますrecv()

  4. への複数の呼び出しは、send()複数の TCP パケットにまたがる可能性があり、recv()パケットごとに への複数の呼び出しが必要になる場合があります。

これを説明するために、 と の 2 つのメッセージが送信されているsend("hello", 5)としsend("world", 5)ます。を呼び出すときに可能な組み合わせを次に示しますrecv()

"hello" "world"
"hel" "lo" "world"
"helloworld"
"hel" "lo" "worl" "d"
"he" "llow" "or" "ld"

アイデアを得ますか?これは単に TCP/IP がどのように機能するかです。すべての TCP/IP 実装は、この断片化を考慮する必要があります。

データを適切に受信するには、 への個々の呼び出しではなく、論理メッセージを明確に分離する必要があります。これは、単一のメッセージを送信するために を複数回send()呼び出す必要があり、単一のメッセージを完全に受信するために複数回呼び出す必要があるためです。したがって、前の例を考慮して、メッセージ間にセパレーターを追加しましょう。send()recv()

send("hello\n", 6);

send("world", 5);
send("\n", 1);

recv()受信側では、文字が受信されるまで何度でも呼び出し\n、その文字に至るまで受信したすべてを処理します。終了時に読み取りデータが残っている場合は、後で処理するために保存しrecv()、次の\n文字まで呼び出しを再開します。

メッセージ間に一意の文字を配置できない場合があります (メッセージ本文ですべての文字を使用できるため、区切り文字として使用できる明確な文字がない場合があります)。その場合、前の整数、構造化ヘッダーなどとして、代わりにメッセージの長さをメッセージの前に付ける必要があります。次にrecv()、完全な整数/ヘッダーを受け取るまで、必要な回数だけ呼び出してから、recv()長さ/ヘッダーが指定するのと同じ数のバイトを読み取るために必要な回数だけ。終了したら、必要に応じて残りのデータを保存し、最初から呼び出しを開始recv()して、次のメッセージの長さ/ヘッダーなどを読み取ります。

于 2013-01-11T22:44:56.313 に答える
1

両方のメッセージが単一の recv 呼び出しで返されることは間違いなく有効です ( Nagle のアルゴリズムを参照)。TCP/IP は順序を保証します (メッセージからのバイトは混合されません)。それらが 1 回の呼び出しで一緒に返されることに加えて、1 つのメッセージが recv への複数回の呼び出しを要求することも可能です (ただし、説明されているように小さいパケットではありそうにありません)。

于 2013-01-11T21:06:59.070 に答える
0

信頼できる唯一のことは、バイトの順序です。それらが recv 呼び出しにどのように分割されているかを当てにすることはできません。場合によっては、終点または途中でマージされることがあります。物事は途中でバラバラになり、独立して到着することもあります。送信者が 12 と 915 を交互に送信しているように聞こえますが、当てにはできません。

于 2013-01-11T21:06:59.780 に答える