SendBufferSize よりも大きなデータを送信する方法について質問したところ、いくつかの部分に分けて送信されるという回答がありました。
2 番目の質問は、このデータをどのように受け取るかということです。ネットワークストリームで完結するのか、それとも分割してしまうのか。
SendBufferSize よりも大きなデータを送信する方法について質問したところ、いくつかの部分に分けて送信されるという回答がありました。
2 番目の質問は、このデータをどのように受け取るかということです。ネットワークストリームで完結するのか、それとも分割してしまうのか。
TCP はメッセージのみのプロトコルではありません。これはストリームベースのプロトコルであり、データの分割を処理します。コア セクションに移動します。TCP の場合、セグメンテーションとフラグメンテーションの 2 つの部分があります。
セグメンテーションは TCP (トランスポート層) で行われます。これは、MSS とウィンドウ サイズの 2 つのパラメーターに依存します。MSS は、デバイスが受信できるセグメントの最大サイズを決定します。MSS は、TCP オプションを介した最初の接続確立中に通信されます。データ フローの各方向は異なる MSS を使用でき、オペレーティング システムがそれを決定します。ただし、ウィンドウ サイズは、受信側ホストからの受信確認とウィンドウ更新を待つ前に、接続の受信側で一度にバッファできるデータの最大値を通信するために、受信側によって TCP ヘッダーで送信されます。つまり、ホストは、受信側のウィンドウ サイズを使い果たす前に、多数のセグメント (MSS の係数) を送信できます。
フラグメンテーションは、IP (ネットワーク層) で 2 つの方法で発生します。送信側と受信側の間の通信経路上に MTU 制限のあるデバイスが存在しない場合、イーサネットの MTU (1500 バイト) だけを満たすためにフラグメンテーションが発生します。ただし、送信側と受信側の間に MTU 制限のある中間デバイスが存在する場合、IP 層 (インターネット プロトコル) がデータグラムの断片化を行うため、最大伝送単位がより小さいリンクを通過できるようにパケットが形成される場合があります ( MTU) を元のデータグラム サイズよりも大きくします。MTU 制限のある中間デバイスの場合、送信者は、パス MTU 検出を展開して、受信者へのネットワーク パスの最小 MTU を決定し、MSS を動的に調整して、ネットワーク内の IP フラグメンテーションを回避する必要があります。パス MTU の検出は、DF (Don' 発信パケットの IP ヘッダーの Fragment) オプション。送信者と受信者の間の通信経路にある、MTU がパケットよりも小さいデバイスは、そのようなパケットをドロップし、デバイスの MTU を含む ICMP「Destination Unreachable (Datagram Too Big)」メッセージで送信者に応答します。この情報により、送信者は想定パス MTU を適切に減らすことができます。
したがって、これは MSS と MTU の間の関係のポイントにつながります。RFC 791 は、「すべてのホストは、最大 576 オクテットのデータグラムを受け入れる準備ができている必要があります (完全に到着するか、フラグメントで到着するかに関係なく)」と述べています。したがって、IP ネットワークの最小 MTU は 576 です。TCP の場合、TCP ヘッダーの 20 バイトと IP ヘッダーの 20 バイトを差し引くと、TCP の標準 MSS として 536 バイトが得られます。
では、再組み立て部分に入りましょう。フラグメンテーションは中間デバイスの MTU に基づいて発生する可能性がありますが、再構成は宛先デバイスでのみ発生します。TCP はセグメンテーションを処理しますが、宛先デバイスでは TCP が順序付けを処理しますが、セグメントの再構成はアプリケーションが処理する必要があります。
したがって、メッセージ全体に基づく通信のみが必要で、信頼性が問題にならない場合は、UDP を選択する必要があります。ただし、分割して大きなデータを送信できる場合、UDP はパケットの順序を保証できず、再送信などのエラー訂正メカニズムがないため、パケットのドロップに対処できないことに注意してください。 .
UDP と同じようにメッセージ ベースの通信を行いたいが、信頼性の高い順序どおりの配信、輻輳制御などの TCP 機能と、それに加えてマルチ ストリーミング、マルチホーミング、インMTU 検出を構築した場合は、SCTP を選択する必要があります。ただし、ネットワークに従来の NAT システムがある場合は、SCTP を UDP にカプセル化する必要がある場合があります。
たとえば UDP とは対照的に、TCP は、同じ形式で受信者に配信される個々の「メッセージ」の送信を許可するプロトコルではありません。むしろ、バイト ストリームを送受信します。
ボンネットの下では、データは IP パケットに分割されます。ただし、デフォルトは8192でSendBufferSize
、単一の IP パケットに収まる値よりもはるかに大きい値です (IP パケットの最大サイズはMTUに関連していますが、ほとんどの場合、 1500 バイト弱)。例:
また、複数Socket.Send()
の のデータがマージされる場合があります ( Nagle のアルゴリズム)。例:
そして、受信者が 2 つのケースを区別する方法はありません。さらに、効率上の理由から、受信側でデータが異なるサイズのバッファーで渡される場合があります。
結論: TCP では、送信されたのと同じ数と同じサイズのパケットを受信することに依存することはできません。それが必要な場合は、Stephen Cleary の提案に従ってサイズ情報を追加するか、UDP などのプロトコルを使用するか、信頼性が必要な場合はSCTPを使用します。ただし、TCP に対する SCTP のその他の改善点にも関心がない限り、これはやり過ぎのように見えます。
.Net がデータの分割を処理します。SendBufferSize よりも大きなパッケージを気付かずに書き込んだり受け取ったりすることができます (パフォーマンスをあまり気にしない場合)。
プロトコルには、メッセージ フレーミングと呼ばれるものが必要です。
おもしろい事実: より小さいメッセージを送信する場合でも、これが必要になりますSendBufferSize
。:)
受信時にデータが分割される可能性があるため、すべてのデータを受信したら再構築する必要があります。