TCPパケットは分割して受信者に届きますか?
たとえば、TCPプロトコルを使用して20バイトを送信する場合、10バイトではなく、10バイトではなく、正確に20バイトを一度に受信することを100%確信できますか?
UDPプロトコルについても同じ質問です。
UDPは信頼性が低く、パケットがまったく到着しない、または異なる順序で到着することはありませんが、単一のパケットはどうですか?到着した場合、それが断片ではなく完全なパケットであることを確認できますか?
TCPパケットは分割して受信者に届きますか?
たとえば、TCPプロトコルを使用して20バイトを送信する場合、10バイトではなく、10バイトではなく、正確に20バイトを一度に受信することを100%確信できますか?
UDPプロトコルについても同じ質問です。
UDPは信頼性が低く、パケットがまったく到着しない、または異なる順序で到着することはありませんが、単一のパケットはどうですか?到着した場合、それが断片ではなく完全なパケットであることを確認できますか?
回答:
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プロトコル用に再構築します。完全なデータが表示されます。
彼らが実際に物理的にすぐに到着するかどうかはわかりません。TCP / UDPの下のデータリンク層は、必要に応じてパケットを分割する場合があります。特に、インターネットまたは管理外のネットワークを介してデータを送信する場合、それを予測することは困難です。
ただし、データが受信側で1つのパケットで到着するか、複数のパケットで到着するかは関係ありません。OSはこれらのパケットの連結を抽象化する必要があるため、アプリケーションにとっては、すべてが一度に到着したように見えます。したがって、カーネルハッカーでない限り、ほとんどの場合、このデータが1つまたは複数のパケットで転送されるかどうかを心配する必要はありません。
UDPの場合、OSは何らかの抽象化も行うため、データを受信するアプリケーションは、データが送信されたパケット数を知る必要がありません。ただし、TCPとの違いは、データが実際に到着する保証がないことです。データが複数のパケットに分割され、そのうちのいくつかは到着し、いくつかは到着しない可能性もあります。受信アプリケーションにとっては、完全であるかどうかに関係なく、データのストリームのように見えます。
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では、ソケットを「栓をする」ことができます(送信を防止)。書き込まれたデータは、コルク処理されている間、単一のユニットに組み立てられます。その後、ソケットが「アンコーク」されると、単一のデータグラムを送信できます。