TCPパケットは断片的に受信機に到着しますか?
たとえば、TCPプロトコルを使用して20バイトを送信する場合、一度に正確に20バイトを受信することを100%確信できますか?
UDPプロトコルについても同じ質問です。
UDPは信頼性が低く、パケットがまったく到着しないか、異なる順序で到着しないことを知っていますが、単一のパケットはどうですか?到着した場合、それが完全なパケットであり、断片ではないことを確認できますか?
TCPパケットは受信者に少しずつ到着しますか?
はい。 IPはフラグメンテーションをサポートしますが、TCPは通常、パフォーマンス上の理由から、パスMTUを決定し、そのパケットをそれよりも小さくしようとします。フラグメンテーションは、データグラムの損失率を壊滅的に増加させます。パスに10%のパケット損失がある場合レート、データグラムを2つのパケットにフラグメント化すると、データグラム損失率はほぼ20%になります(いずれかのパケットが失われると、データグラムは失われます)。
ただし、これについて心配する必要はありません。また、TCPレイヤーも同様です。IPレイヤーは、パケットをデータグラム全体に再構成します。
例:TCPプロトコルを使用して20バイトを送信した場合、一度に正確に20バイトを受信することを100%確信できますか?
いいえ、しかしそれはパケットとは何の関係もありません。 TCPは、基本的に、アプリケーションメッセージの境界を保持しないバイトストリームプロトコルです。
UDPプロトコルについても同じ質問です。 UDPは信頼性が低く、パケットがまったく到着しないか、異なる順序で到着しないことを知っています。
TCPについても同様です。パケットはパケットです。違いは、TCPにはプロトコルに組み込まれている再試行と並べ替えがありますが、UDPにはありません。
1パケットはどうですか?到着した場合、それが完全なパケットであり、断片ではないことを確認できますか?
いいえ、でもそれはあなたの問題ではありません。 UDPプロトコルは、データグラムの再構成を処理します。それはその仕事の一部です。 (実際には、IPプロトコルはUDPプロトコルに対してこれを行うので、UDPは単にIPの上に階層化されることによってそれを行います。)データグラムが2つのパケットに分割される場合、IPプロトコルはそれをUDPプロトコル用に再構成します。完全なデータが表示されます。
彼らが本当に物理的にすぐに到着するかどうかはわかりません。 TCP/UDPの下のデータリンク層は、必要に応じてパケットを分割する場合があります。特に、インターネットや自分の制御範囲外のネットワークを介してデータを送信する場合、それを予測することは困難です。
しかし、データが1つのパケットで到着するか、複数のパケットで受信者に到着するかに関係なく。 OSはこれらのパケットの連結を抽象化する必要があるため、アプリケーションでは、すべてが一度に到着したように見えます。したがって、カーネルハッカーでない限り、ほとんどの場合、このデータが1つまたは複数のパケットで転送されるかどうかを心配する必要はありません。
UDPの場合、OSはいくつかの抽象化も行うため、データを受信するアプリケーションは、データが送信されたパケット数を知る必要はありません。ただし、TCP=との違いは、データが実際に到着する保証がないことです。データが複数のパケットに分割され、一部が到着し、一部が到着しない可能性もあります。受信側のアプリケーションでは、それが完全であるかどうかに関係なく、とにかくデータのストリームのように見えます。
例。隣接する文字のブロックは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
データは必ずしも同じ順序である必要はなく、必ずしも受信されるとは限りませんが、メッセージは完全に保持されます。
例:TCPプロトコルを使用して20バイトを送信する場合、10バイトではなく20バイトを正確に一度に受信することを100%確信できますか?
いいえ、TCPはストリームプロトコルであり、データを順番に保持しますが、メッセージごとにグループ化しません。一方、UDPはメッセージ指向ですが、信頼性がありません。 [ 〜#〜] sctp [〜#〜] 両方の長所がありますが、NATはインターネットを破壊するため、ネイティブでは使用できません。
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では、ソケットが「コーキング」される可能性があります(送信が阻止されます)。コルクされている間、書き込まれたデータは1つのユニットにまとめられます。その後、ソケットが「切断」されると、単一のデータグラムを送信できます。