I. TCPの特徴
- TCPは、コネクション指向の信頼性の高いバイトストリーミングサービスを提供します。
- TCP 接続では、2 つのパーティだけが互いに通信します。TCPではブロードキャストとマルチキャストは使用できません。
- TCPは、チェックサム、確認応答、再送信を使用して、信頼性の高い伝送を保証します。
- TCPはデータをセクションにソートし、累積検証を使用して、データが同じ順序で重複していないことを確認します。
- TCPは、輻輳制御のためにウィンドウのサイズを動的に変更することにより、フロー制御を実装するためにスライディングウィンドウメカニズムを使用します。
注: TCPは、データが相手によって受信されることを保証するものではありません。したがって、TCPは100%信頼できるプロトコルではありません。TCPが提供できるのは、データの確実な配送か、失敗の確実な通知だけです。
II.TCPメッセージ・フォーマット
TCPメッセージイメージの解釈
TCPメッセージの詳細
送信元ポートと宛先ポート
それぞれ2バイトを占め、送信元ポート番号と宛先ポート番号がそれぞれ書き込まれます。例えば、クライアントのポート番号が10000、サーバのポート番号が9999の場合、クライアントは送信元ポート番号が10000、宛先ポート番号が9999のメッセージセグメントを送信し、サーバは逆のメッセージセグメントを送信します。
プロダクトキー
データの先頭バイトのシーケンス番号を示します。データの先頭バイトのシーケンス番号を示します。 TCPのデータのやり取りはシーケンス番号に基づいて行われるため、送信側はシーケンス番号でデータの送信やタイムアウト再送を制御し、受信側はシーケンス番号で並び替えを制御します。
受信側は、最初のバイトのシーケンス番号+データ数から最後のバイトのシーケンス番号を計算し、それに1を加えてアンサーとして使用することができます。
232232バイトは4GBなので、再利用されたシーケンス番号で表されるデータは、正常に反対側の端に到達していることが保証されます。
確認番号
これは 4 バイトを占め、次回受信する予定のシーケンス番号を示します。例えば、サーバがクライアントからメッセージセグメントを受信した場合、シーケンス番号フィールドの値は501で、データの長さは200と計算できるので、サーバは最後のバイトのシーケンス番号が700であることがわかります。応答メッセージセグメント
データオフセット
4ビットを占め、TCPメッセージセグメントの最初のデータがセグメントの先頭からどの程度離れているかを示します。TCP セグメントの最初の部分の長さは、20 バイトから 60 バイトまで可変であるため、データの先頭を見つけるためのフィールドが必要です。
データ・オフセットは 4 バイトの倍数を表し、4 ビット・バイナリは最大 15 を表すことができるため、データ・オフセットは最大 4 * 15 = 60 となり、これは TCP メッセージ・セグメントの最初の部分の最大長でもあります。
予約
現在使用中ではありません。
制御ビット
TCPメッセージセグメントのヘッダーには、メッセージセグメントの性質を表す6つの制御ビットがあります。
Urgent URG メッセージ・セグメント内のデータが緊急であり、すぐに処理する必要があることを示します。受信側はこのタイプのメッセージ・セグメントを受信すると、通常の処理のようにデータを受信バッファの最後に追加するのではなく、アプリケーションが緊急のデータをすぐに読めるようにバッファの最初に挿入します。
例えば、Ctrl + C をタイプした場合、この割り込みメッセージはバッファのヘッダーに配置され、そうでない場合は、アプリケーションがすべてのデータを処理したときにのみ、終了メッセージを受信します。
この制御ビットは、緊急ポインタと組み合わせて使用する必要があります。
ACKの確認
確認応答番号は、ACKビットが1に設定されている場合にのみ有効です。 TCPでは、コネクション確立後に送信されるすべてのセグメントについて、ACKビットを1に設定する必要があります。
プッシュPSH
送信側がデータを相手側にすぐに送れるようにしたい場合、TCP は PSH 位置 1 をメッセージセグメントの先頭に置き、受信側も同様に PSH 位置 1 を持つメッセージセグメントのデータをできるだけ早くアプリケーションに通知します。TCP は PUSH 操作を使用するタイミングを自分で決定するため、この制御ビットはめったに使用されません。
リセット RST
コネクションにエラーがあり、直ちにコネクションを閉じる必要があることを示すた めに、リセットに使用されます。TCP がリセット・メッセージ・セグメントを受信すると、アプリケーションに接続がリセッ トされたことを通知し、その後接続を閉じます。
同期SYN
接続確立時にシーケンス番号を同期させるために使用され、相手に開始シーケンス番号を通知します。バッファの開始点は、相手のシリアル番号に基づいて初期化することができます。
SYN=1、ACK=0は接続要求セグメント、SYN=1、ACK=1は接続受信セグメントを示します。
FINの終了
コネクションを解放するために使用され、メッセージ・セグメントの FIN 制御ビットは、データが送信され、コネクションがクローズされるのを待っていることを示す 1。
イチジク
メッセージセグメントを送信する側が受信できるバイト数を示す2バイト占有。
ウィンドウの値の範囲は0~2の16乗~1乗です。
チェックサム
2バイトを占め、メッセージセグメントにエラーがあるかどうかをチェックするために使用されます。送信側は送信されたセグメントに従ってテストを計算し、セグメントヘッダを埋め、受信側は受信したセグメントに従って再計算します。
緊急ポインタ
メッセージセグメントは、緊急データと通常データの両方を含むことができるため、このフィールドは両者を区別するために使用されます。緊急 URG 制御ポジション 1 に対してのみ有効です。
オプション
TCPメッセージのヘッダの最初の20バイトは固定です。TCP メッセージはヘッダにオプションを追加することもあり、このセクションの長さは固定されておらず、アプリケーションのシナリオによって異なります。
このセクションでよく使われるオプションは以下の通りですが、これらに限定されるものではありません:
1.Maximum Message Segment(最大メッセージ・セグメント):各 TCP メッセージ・セグメントで送信されるデータの最大長を決定するために使用されます。
2.ウィンドウ拡張オプション:TCPウィンドウサイズは最大64K、ほとんどの場合はこれで十分ですが、スループットを向上させるために、ウィンドウを拡張する必要があることがあります。
3.タイムスタンプオプション: RLLの計算に使用でき、TCP輻輳制御に使用できます。
III.TCPコネクションの確立
最初の段階では、クライアントもサーバーもCLOSEDの状態です。クライアントは能動的に接続を開き、サーバは受動的に接続を開きます。
スリーハンドシェイクの流れ
- TCPサーバ・プロセスは、まず送信制御ブロックTCBを作成し、クライアント・プロセスからの接続要求を受け付ける準備を常に整えています;
- また、TCPクライアント・プロセスは、最初に伝送制御ブロックTCBを作成し、その後、サーバーに接続要求メッセージを送信します。これは、メッセージ・ヘッダSYN=1と同じ部分であり、初期シーケンス番号seq=xを選択しながら、この時点で、TCPクライアント・プロセスはSYN-SENT状態に入ります。tcpは、SYNメッセージ・セグメントはデータを運ぶことはできませんが、シーケンス番号を消費する必要があると規定しています。
- TCPサーバは要求メッセージを受信すると、接続に同意する場合は確認メッセージを送信します。この時点で、TCPサーバプロセスはSYN-RCVDステートに入ります。このメッセージもデータを運ぶことはできませんが、ここでもシーケンス番号を消費します。
- TCP クライアント・プロセスは確認を受信しますが、サーバにも確認を送信します。確認メッセージには、ACK=1、ack=y+1、およびそれ自身のシーケンス番号seq=x+1があり、この時点でTCP接続が確立され、クライアントはESTABLISHED状態になります。
- サーバがクライアントの確認を受け取ると、サーバもESTABLISHED状態になり、その後、双方が通信を開始することができます。
なぜTCPクライアントは最後に確認応答を送るのですか?
一言で言えば、主に失敗した接続要求メッセージが突然サーバーに再送信され、エラーが発生するのを防ぎます。
接続を確立するために2つのハンドシェイクの使用は、このようなシナリオがあると仮定した場合、クライアントは、接続するための最初の要求を送信し、ネットワークノード内のタイムラグが長すぎるため、失われなかっただけで、TCPクライアントは、確認応答メッセージの受信が遅れているため、サーバーが受信していないと考え、この時点でサーバーにこのメッセージを再送信した後、クライアントとサーバーは、接続を完了するために2つのハンドシェイクの後にデータを転送し、接続を閉じます。この時点で、要求の接続の前のラグは、ネットワークがサーバーに到達するために滑らかである、このメッセージは無効である必要がありますが、2つのハンドシェイクのメカニズムは、クライアントとサーバーが再び、不必要なエラーやリソースの無駄につながる接続を確立することができます。
3回のハンドシェイクが使用される場合、失敗したメッセージが送信されても、サーバは失敗したメッセー ジを受信して確認応答を返しますが、クライアントは再度確認応答を送信しません。サーバは確認応答を受け取らないので、クライアントが接続を要求していないことがわかります。
データ転送が完了すると、両当事者は接続を解放できます。最初の段階では、クライアントもサーバもESTABLISHEDの状態にあり、その後クライアントは能動的に閉じられ、サーバは受動的に閉じられます。
4つの波プロセス
- クライアント・プロセスは接続解放メッセージを発行し、データの送信を停止します。リリース・データ・メッセージの最初の部分であるFIN=1のシーケンス番号はseq=uで、この時点でクライアントはFIN-WAIT-1状態になります。 TCPは、FINメッセージセグメントがデータを運んでいなくてもシーケンス番号を消費することを指定しています。
- サーバはコネクション解放メッセージを受信し、ACK=1、ack=u+1という確認メッセージを送信し、自身のシーケンス番号seq=vを持ってきます。この時点で、サーバはCLOSE-WAIT状態になります。TCPサーバは上位のアプリケーション・プロセスに通知し、サーバへのクライアントは解放されます。この時点で、サーバはセミクローズ状態、つまりクライアントから送信されるデータはなくなります。しかし、サーバーがデータを送信しても、クライアントはそれを受け入れなければなりません。この状態はしばらくの間、つまりCLOSE-WAIT状態の全期間続きます。
- クライアントがサーバから確認応答を受信すると、この時点でクライアントはFIN-WAIT-2状態になり、サーバがコネクション解放メッセージを送信するのを待ちます。
- サーバは最後のデータを送信すると、FIN=1、ack=u+1というコネクション解放メッセージをクライアントに送信します。セミクローズ状態であるため、この時点でのシーケンス番号がseq=wであると仮定すると、サーバはさらにデータを送信している可能性があります。
- サーバからのコネクション解放メッセージを受信したクライアントは、ACK=1、ack=w+1、自身のシーケンス番号はseq=u+1という確認応答を発行しなければなりません。この時点でクライアントはTIME-WAIT状態に入ります。TCPコネクションはこの時点では解放されず、2***MSL後にCLOSED状態になり、クライアントが対応するTCBを破棄しなければならないことに注意してください。
- サーバは、クライアントから確認応答を受け取るとすぐにCLOSED状態に入ります。同様に、TCBを破棄すると、このTCP接続は終了します。ご覧のように、サーバはクライアントより少し早くTCP接続を終了します。
なぜクライアントは2MSLを待つことになるのでしょうか?
MSL では、TCP は実装によって異なる MSL 値を設定することができます。
まず、クライアントが最後に送信したACKメッセージがサーバに届くようにするために、このACKメッセージが失われる可能性があるため、サーバから見ると、私はすでに切断を要求するFIN+ACKメッセージを送信しており、クライアントはまだ私に応答していないため、私が送信した切断要求メッセージは受信されなかったということになるはずなので、サーバは再度再送信し、クライアントはこの再送信されたメッセージをこの2MSL時間内にこの再送メッセージを受信し、応答メッセージを送り、2MSLタイマーを再スタートします。
第二に、「3つのハンドシェイク」で述べたような「無効化された接続要求セグ メント」がこの接続に現れるのを防ぎます。クライアントが最後の確認メッセージを送信した後、接続の間に生成された すべてのメッセージセグメントは、2MSLの間にネットワークから削除されます。このようにして、古いコネクションからのリクエストメッセー ジは新しいコネクションには現れません。
接続を確立するには3回のハンドシェイクが必要ですが、接続を閉じるには4回必要なのはなぜですか?
コネクションを確立する場合、サーバはLISTEN状態にあり、コネクション確立を要求するSYNメッセージを受信し、ACKとSYNを1つのメッセージとしてクライアントに送信します。接続を終了するとき、サーバは相手からFINメッセージを受信しますが、これは相手がデータを送信しなくなったが、まだデータを受信できることを意味するだけで、相手にはすべてのデータを送信していないかもしれないので、すぐに終了するか、相手にいくつかのデータを送信してから、接続を終了することに同意することを示すために相手にFINメッセージを送信します。したがって、ACKとFINは別々に送信されるのが一般的です。
接続が確立しているにもかかわらず、クライアントが突然失敗した場合は?
TCPにはキープアライブタイマーもあります。 クライアントが失敗した場合、サーバは無駄に待ち続けてリソースを浪費するわけにはいきません。サーバはクライアントからのリクエストを受信するたびにこのタイマをリセットします(通常は2時間に設定されています)。2時間クライアントからデータを受信しなかった場合、サーバはプローブ・メッセージ・セグメンテーションを送信し、以後75秒ごとに送信します。プローブメッセージを10回送信しても応答がない場合、サーバはクライアントの接続に失敗したと判断し、接続を切断します。