TCPソケットプログラミングでは、 recv()
0が返される場合、反対側が接続を閉じたことを示していると見なされます。ただし、AFAIK、TCP RFCは、TCPのペイロードを> 0にすることを義務付けていません。したがって、理論的には、TCPスタックはペイロード0のメッセージを受信できます。
したがって、基本的に私の質問は、recv()
サイズが0のペイロードのパケットを受信した場合に何が返されるかということです。0が返された場合、閉じた接続の表示とどのように区別しますか。
ペイロードサイズが0のTCPセグメントはどこにでもあり、実際のほとんどすべてのTCPストリームで発生します。これらは、一方が他方からのデータの受信を確認したいときに送信されますが、独自に送信するデータはありません。(これらは一般に「ACKパケット」として知られていますが、「ACKパケット」はデータを含まない通常のセグメントです)。
このようなパケットにはユーザーアプリケーションに配信するデータが含まれていないためrecv()
、返されることはありませんrecv()
。実際のデータが到着するまでブロックを続けます。0を返す場合recv()
は、もう一方の端が接続の側を閉じており、これ以上データを送信しないことを明確に示しています。
TCPはストリーム指向であることに注意してください。単一の呼び出しによって返されるデータと単一のTCPセグメント内のデータの間に1対1のマッピングはありません。recv()
1回のrecv()
呼び出しで、複数のTCPセグメントと重複するデータのブロックが返される場合があり、1回のTCPセグメントのデータが複数のrecv()
呼び出しで返される場合があります。TCPセグメント間の境界は、BSDソケットAPIを使用するアプリケーションには表示されません。このような境界が必要な場合は、TCPストリーム内でアプリケーション層プロトコルを使用して実装するか、UDPなどのデータグラム指向のプロトコルを使用する必要があります。
そうです、POSIXによると、recv
が返された場合0
、接続はピアによって正しくシャットダウンされます。
誰かがゼロサイズのペイロードでTCPパケットを送信することに成功した場合、OSは、そのソケットでのシステムコールでブロックされているプロセスにデータを返す必要はありません。recv
TCPペイロードは、単一のシステムコール中に返される必要のあるデータグラムのシーケンスではなく、OSによってランダムにスライスされる可能性のある連続ストリームを形成することに注意してください。