好奇心から、(Java ソケットを使用して) ポートへの接続を確立するときに実際に送信されるデータの量。Socket オブジェクトのサイズですか? SocketConnection オブジェクト?
2 に答える
TCP ネットワーク接続に関するあなたの理解は、それらを電気回路と混同しているようです。(あなたのバックグラウンドを考えると、理解できます。)
物理的な観点からは、接続などはなく、データ パケットのみです。TCP プロトコルを介して、2 つのデバイスが論理(つまり、ソフトウェア) 接続を確立することに同意します。接続は、クライアントが最初にリモート ホストにデータを送信し (SYN)、サーバーがクライアントにデータを送り返し (SYN-ACK)、クライアントが最終確認応答 (ACK) を送信することによって確立されます。 このすべてのネゴシエーションは必然的に帯域幅を消費し、接続を終了するときは、データの送信を再開するために完全に新しい接続をネゴシエートする必要があります。
たとえば、自分のマシンからローカル Web サーバー 192.168.1.2:80 に接続します。
まず、私のマシンは TCP SYN を送信します。これにより、ネットワーク経由で 66 バイトが送信されます: (ヘッダーは で区切られます|
)
0000 00 24 8c a9 4c b4 00 1e 68 66 20 79 08 00|45 00 .$..L... hf y..E.
0010 00 34 53 98 40 00 80 06 00 00 c0 a8 01 0b c0 a8 .4S.@... ........
0020 01 02|36 0a 00 50 09 ef 3a a7 00 00 00 00 80 02 ..6..P.. :.......
0030 20 00 50 c8 00 00 02 04 05 b4 01 03 03 02 01 01 .P..... ........
0040 04 02 ..
最初の 14 バイトはイーサネット フレームで、このパケットの宛先 MAC アドレスを指定します。通常、これは上流のルーターですが、この場合、サーバーはたまたま同じスイッチ上にあるため、マシンのMACアドレス 00:24:8c:a9:4c:b4 になります。送信元 (my) MAC が、ペイロード タイプ (IP、0x0800) と共に続きます。次の 20 バイトは IPv4 ヘッダーで、その後に 32 バイトの TCP ヘッダーが続きます。
サーバーは 62 バイトの SYN-ACK で応答します。
0000 00 1e 68 66 20 79 00 24 8c a9 4c b4 08 00|45 00 ..hf y.$ ..L...E.
0010 00 30 69 b9 40 00 80 06 0d b1 c0 a8 01 02 c0 a8 .0i.@... ........
0020 01 0b|00 50 36 0a d3 ae 9a 73 09 ef 3a a8 70 12 ...P6... .s..:.p.
0030 20 00 f6 9d 00 00 02 04 05 b4 01 01 04 02 ....... ......
ここでも、イーサネット ヘッダーが 14 バイト、IP ヘッダーが 20 バイト、TCP ヘッダーが 28 バイトです。ACK を送信します。
0000 00 24 8c a9 4c b4 00 1e 68 66 20 79 08 00|45 00 .$..L... hf y..E.
0010 00 28 53 9a 40 00 80 06 00 00 c0 a8 01 0b c0 a8 .(S.@... ........
0020 01 02|36 0a 00 50 09 ef 3a a8 d3 ae 9a 74 50 10 ..6..P.. :....tP.
0030 fa f0 83 78 00 00 ...x..
14 + 20 + 20 = 54 バイトがネットワーク経由で送信されます (ちなみに、これは可能な最小の TCP パケット サイズです。SYN および SYN-ACK パケットは、オプションが含まれているため、より大きくなります)。
これにより、接続を確立するためにワイヤ上で最大182バイトが追加されます。これで、サーバーへの実際のデータの送信を開始できます。
0000 00 24 8c a9 4c b4 00 1e 68 66 20 79 08 00 45|00 .$..L... hf y..E.
0010 01 9d 53 9d 40 00 80 06 00 00 c0 a8 01 0b c0 a8 ..S.@... ........
0020 01 02|36 0a 00 50 09 ef 3a a8 d3 ae 9a 74 50 18 ..6..P.. :....tP.
0030 fa f0 84 ed 00 00|47 45 54 20 2f 20 48 54 54 50 ......GE T / HTTP
0040 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20 66 73 0d 0a /1.1..Ho st: fs..
...
14 イーサネット + 20 IP + 20 TCP + データ (この場合は HTTP)。
したがって、TCP 接続を確立するのに ~182 バイト、TCP 接続を終了するのにさらに 162 ~ 216 バイトかかることがわかります (4 方向 FIN ACK FIN ACK か、より一般的な 3 方向 FIN FIN-ACK かによって異なります)。 ACK 終了ハンドシェイクが使用されます)、接続を切断して再接続することによって接続を「パルス」するために、最大 400 バイト近く追加されます。
すでに確立されている接続を介して 1 バイトのデータを送信するために使用する 55 バイトと比較すると、これは明らかに無駄です。
やりたいことは、1 つの接続を確立してから、必要に応じてデータを送信することです。本当に帯域幅に制約がある場合は、UDP を使用できます (ハンドシェークがまったく必要なく、パケットあたり 14 イーサネット + 20 IP + 8 UDP バイトのオーバーヘッドしかありません)。ただし、信頼性の低いトランスポートを使用するという問題に直面します。失われたパケットを自分で処理する必要があります。
TCP パケットの最小サイズは 40 バイトです。接続を作成するには、クライアントから 2 つ、サーバーから 1 つ、合計 3 つの交換パケットが必要です。接続を閉じるには、さらに 4 つのパケット (各方向に 2 つ) が必要です。以下の @ josh3736 のコメントに従って発信 FIN と ACK を組み合わせることができるように、接続交換の最後のパケットにもデータを含めることができます。