TCPパケットとUDPパケットを分割できますか?


41

TCPパケットは分割して受信者に届きますか?

たとえば、TCPプロトコルを使用して20バイトを送信する場合、10バイトではなく、10バイトではなく、正確に20バイトを一度に受信することを100%確信できますか?

UDPプロトコルについても同じ質問です。
UDPは信頼性が低く、パケットがまったく到着しない、または異なる順序で到着することはありませんが、単一のパケットはどうですか?到着した場合、それが断片ではなく完全なパケットであることを確認できますか?


7
明確化のポイント:TCPセグメントおよびUDPデータグラムと呼ばれます。それらはパケットではありません。TCP =セグメント、UDP =データグラム、IP =パケット、イーサネット=フレーム、他のすべてのレイヤー(AFAIK)では、PDU(プロトコルデータユニット)と呼ばれています。
joeqwerty

回答:


33

TCPパケットは分割して受信機に到着できますか?

はい。IPは断片化をサポートしますが、TCPは一般にパスMTUを決定し、パフォーマンス上の理由でパケットよりもパケットを小さくしようとします。断片化は、データグラム損失率を壊滅的に増加させます。パスのパケット損失率が10%の場合、データグラムを2つのパケットに断片化すると、データグラム損失率はほぼ20%になります。(いずれかのパケットが失われた場合、データグラムは失われます。)

ただし、これについて心配する必要はなく、TCP層も心配する必要はありません。IP層は、パケットをデータグラム全体に再構成します。

たとえば、TCPプロトコルを使用して20バイトを送信する場合、10バイトではなく、正確に20バイトを受信することを100%確信できますか?

いいえ、しかし、それはパケットとは何の関係もありません。TCPは、基本的に、アプリケーションメッセージの境界を保持しないバイトストリームプロトコルです。

UDPプロトコルについても同じ質問です。UDPは信頼性が低く、パケットがまったく届かない、または異なる順序で届かないことがわかっています。

TCPについても同様です。パケットはパケットです。違いは、TCPにはプロトコルに組み込まれている再試行と並べ替えがありますが、UDPにはないことです。

しかし、1パケットはどうですか?到着した場合、断片ではなく完全なパケットであることを確認できますか?

いいえ、しかしそれはあなたの問題ではありません。UDPプロトコルは、データグラムの再構成を処理します。それはその仕事の一部です。(実際には、IPプロトコルはUDPプロトコルに対してこれを行うため、UDPは単にIPの上に階層化することによってそれを行います。)データグラムが2つのパケットに分割される場合、IPプロトコルはUDPプロトコル用に再構築します。完全なデータが表示されます。


10
初心者の読者のために最後の部分を明確にする価値があるかもしれません:あなたは 問題のデータグラムの完全なデータ見るでしょう。分割されたパケットのいずれかが失われると、データグラムが失われ、UDPレイヤーはそれを認識しなくなります。データグラム内のすべてのパケットが受信される限り、それらはIP層で組み立てられ、UDP層に渡されます。これは、データストリームに「チャンク」が欠落する可能性を排除するものではありません。つまらないものではありませんが、このことを学んでいたとき、教科書を2回目または3回目が通過するまで、IPフラグとUDP損失の違いを理解できませんでした。
ジャスティン

20

彼らが実際に物理的にすぐに到着するかどうかはわかりません。TCP / UDPの下のデータリンク層は、必要に応じてパケットを分割する場合があります。特に、インターネットまたは管理外のネットワークを介してデータを送信する場合、それを予測することは困難です。

ただし、データが受信側で1つのパケットで到着するか、複数のパケットで到着するかは関係ありません。OSはこれらのパケットの連結を抽象化する必要があるため、アプリケーションにとっては、すべてが一度に到着したように見えます。したがって、カーネルハッカーでない限り、ほとんどの場合、このデータが1つまたは複数のパケットで転送されるかどうかを心配する必要はありません。

UDPの場合、OSは何らかの抽象化も行うため、データを受信するアプリケーションは、データが送信されたパケット数を知る必要がありません。ただし、TCPとの違いは、データが実際に到着する保証がないことです。データが複数のパケットに分割され、そのうちのいくつかは到着し、いくつかは到着しない可能性もあります。受信アプリケーションにとっては、完全であるかどうかに関係なく、データのストリームのように見えます。


ネットワークカードドライバーは、カーネルではなくパケットを再構成しますか?
bluehallu

2
@Hallucynogenyc:状況に変化がない限り、インターネットプロトコルは576バイトを超えるパケットを移動中の任意の時点で分割できるように設計されていますが、最終的な受信者以外が再結合することはありません。私は、より大きなパケットの使用はほとんどの場合、オーバーヘッドを削減するための努力だったと考えていると思います。パケットが途中で分割されると、オーバーヘッドが既に発生しているため、最終受信者が何の助けにもならないうちに再結合し、再分割する必要がある場合は傷つく可能性があります。
supercat

576バイトを超えるパケットは分割される可能性がありますが、そのサイズを下回るパケットは分割されない可能性があります。分割パケットを処理できない組み込みシステムは、それより大きいものを要求しないようにする必要があります。
supercat

1
@ mauro.stettler:「ベアメタル」でTCPスタックを作成しました(多数のネットワークインターフェイスチップと直接通信するコードを作成しています)。576バイトの制限があるリンクと通信して、長いパケットを分割するハードウェアの場合は簡単です。パケットの再組み立てすることで多くの 1がそれらのいずれかがいっぱいで受信される前に、多くの異なるパケットの一部を受け取ることができる、特に以来、より複雑。
supercat

ipv4のIPパケットの各ホップに必要な「保証された最大サイズ」があるため、小さなペイロード(約10または20バイトは問題ないはずです)に分割されないという希望があります。 IPヘッダー、および下位レベルのヘッダーはカウントしません)。en.wikipedia.org/wiki/Maximum_transmission_unitの最初の表を参照してください。HOSTSに必要な最小サイズの576バイトとは異なります(つまり、すべての中間ホップではなく、送信の開始または終了)。そして注意してください:ペイロードはさらに低くなります(各レイヤーのヘッダーがスペースをとるので)。
オリビエデュラック

14

例。連続する文字のブロックは、send()呼び出しに対応します。

TCP:

Send: AA BBBB CCC DDDDDD E         Recv: A ABB B BCC CDDD DDDE

送信されるすべてのデータは順番に受信されますが、必ずしも同じチャンクで受信されるとは限りません。

UDP:

Send: AA BBBB CCC DDDDDD E         Recv: CCC AA E

データは必ずしも同じ順序である必要はなく、必ずしもまったく受信されるわけではありませんが、メッセージ全体が保持されます。


5

たとえば、TCPプロトコルを使用して20バイトを送信する場合、10バイトではなく、正確に20バイトを受信することを100%確信できますか?

いいえ、TCPはストリームプロトコルであり、データを順番に保持しますが、メッセージごとにグループ化しません。一方、UDPはメッセージ指向ですが、信頼できません。SCTPには両方の長所がありますが、NATがインターネットを破壊するため、ネイティブに使用できません。


1

TCPストリームの最初に20バイトを送信した場合、2つの10バイトの断片として到着しないという保証があります。これは、TCPスタックがそのような小さなセグメントを送信しないためです。最小MTUサイズがあります。ただし、送信がストリームの途中にある場合、すべてのベットはオフになります。プロトコルスタックがセグメントを埋めて送信するために10バイトのデータを取得し、次の10バイトが別のセグメントに移動する可能性があります。

プロトコルスタックは、データをチャンクに分割し、キューに入れます。チャンクサイズはパスMTUに基づいています。送信操作を実行しても、まだキューに入れられたデータが保留中の場合、プロトコルスタックは通常、キューの末尾にあるセグメントを覗き、そのセグメントにデータを追加する余地があるかどうかを確認します。部屋は1バイトと小さい場合があるため、2バイトの送信でさえ2つに分割される可能性があります。

一方、データのセグメンテーションは、部分的な読み取りが可能であることを意味します。受信操作は、わずか1つのセグメントが到着したときに目覚め、データを取得する可能性があります。広く実装されているソケットAPIでは、受信呼び出しは20バイトを要求できますが、10で返される可能性があります。もちろん、20バイトが受信されるか、接続が切断されるまでブロックするバッファー層を構築できます。POSIXの世界では、そのAPIを標準のI / Oストリームにすることができfdopenます。ソケット記述子を使用してFILE *ストリームを取得し、freadそれを使用してバッファーを埋めることで、必要な数のread呼び出しで完全な要求を満たすことができます。

UDPデータグラムはデータをフレーム化します。送信呼び出しごとにデータグラムが生成されます(ただし、コーキングについては以下を参照してください)。反対側は完全なデータグラムを受け取ります(そして、ソケットAPIでは、それを保持するのに十分な大きさのバッファーを指定する必要があります。そうしないと、データグラムが切り捨てられます)。大きなデータグラムはIPフラグメンテーションによって断片化され、アプリケーションに対して透過的に再構築されます。フラグメントが欠落している場合、データグラム全体が失われます。そのような状況では、部分的なデータを読み取る方法はありません。

インターフェイスには、複数の操作で単一のデータグラムを指定できる拡張機能があります。Linuxでは、ソケットを「栓をする」ことができます(送信を防止)。書き込まれたデータは、コルク処理されている間、単一のユニットに組み立てられます。その後、ソケットが「アンコーク」されると、単一のデータグラムを送信できます。


これはfalseです。10または20バイトのペイロードでパケを送信すると、1つのパケが生成され、ipv4を使用する場合は、他のプロトコルレイヤーのすべてのヘッダーを追加する場合でも適合します。 68バイト以内に収まるため、1パケットですべてのホップを確実に通過します。Tcpスタックは(最初の段落で示唆されているように)「mtuがいっぱいになるまで(つまり、適切なサイズのパケットを作成するために複数のパケットを追加する)」パケットを送信しません!...この挙動は多くのことを壊します(それらの「フラグメント」が同じホストのペアに送信された場合でも)
オリビエデュラック

@OlivierDulac:それは間違っています。TCPは通常、必要に応じてパケットを生成し、ネットワークの使用を最適化しようとするため、Kazが説明したように、20バイトが2つの異なるパケットになる可能性があります。これは、TCP_NODELAYソケットオプションを使用して制御できます。これにより、アプリケーションでより高速なTCPネットワークが必要な場合に、パケットにバイトをディスパッチするNaglesアルゴリズムが無効になります。また、68バイトはパケット長の事実上の標準ではありません。1500バイトがより一般的なデフォルト値です(これは実際にネットワークによって異なります)。
jjmontes
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.