TCPの概要

TCPは理論としては非常に複雑ですが、このあたりの知識は ネットワークの設定などをやる程度でははっきりいってほとんど 不要だと思います。まあ、知っているに越したことはないのですが。

強いて言えば、以下の場合には必要となるでしょう。

もっとも、このレベルになるとUNIX自体の知識も必要条件に なってくると思います。あ、ファイアーウォールは Windows NT で動くやつの方が多いかな?ということなので、そこまでは いらないという方は適当に読み飛ばしてください。

  1. TCP の特徴

    TCPとUDPの、ユーザ側から見た基本的な違いを以下に示します。

    TCPとUDPの違い
    UDPTCP
    接続形態1:1 および 1:n どちらも可能1:1 のみ
    アプリケーションの特定方法UDPポート番号TCPポート番号
    送受信の単位パケット(*1)ストリーム(*2)
    宛先までの到達保証なしあり
    送信エラー時の動作パケット破棄自動的に再送
    事前のアプリケーション同士の接続動作
    (コネクションの確立)
    不要(*3)必要(*4)
    処理の重さ軽い重い

    • (*1)パケット……送信側が送ったパケットが、 そのままの形で受信側に届きます。明確な電文の区切りがあります。
    • (*2)ストリーム……送信されるデータは無限の長さを持ちます。 電文の区切りがありません。
    • (*3)コネクションレス型通信と呼ばれます。
    • (*4)コネクション型通信と呼ばれます。

    TCPの方がUDPより高級なプロトコルであることは明白ですね。 これらのことを実現するために、TCPでは以下のことが必要となります。

    • コネクション(接続性)の確立
    • 送達確認(ACK)
    • 到着順序保証
    • フロー制御

    では、1つずつ説明していきましょう。 必要に応じてTCPパケット を参照してください。

  2. コネクション(接続性)の確立

    まず大前提として、アプリケーションはTCPで接続をオープンする際に、 自分が能動的(active)に接続しにいくのか、受動的(passive)に相手側 からの接続を待つのかを前もって決定しておく必要があります。 前者をクライアント・アプリケーション(以下クライアント)、 後者をサーバ・アプリケーション(以下サーバ)と呼びます。

    接続確立時のシーケンスは以下のようになります。 これを3ウェイ・ハンドシェークと呼んでいます。 便宜上、クライアント←サーバの転送を下り、その逆を上りと称します。 また、SYN, ACK ビットとはTCPパケット の14バイト目(下6ビット)にあるフラグの中の各ビットのことです。

    3ウェイ・ハンドシェーク
    サーバクライ
    アント
    説明
    SYN上りコネクションの確立を試みる。
    ACK+SYNSYNに対するACKを立てる (上りコネクションの確立を承認)とともに、 自らもSYNビットを立てることにより、下りコネクションの確立を試みる。
    ACK下りコネクションの確立を承認する。

    これを見てもわかるように、上りと下りで論理的には別々の コネクションを確立するような感じになります。つまり、 TCPは全2重(同時に双方向の通信ができる)通信を行うということです。

  3. 送達確認(ACK)

    前の節ですでに登場しましたが、TCPでは肯定応答をするために ACK ビットを使用します。コネクションの確立のところでは、 ACKはSYN(接続要求)に対する肯定応答として使用されました。 いったん接続が確立されると(3ウェイ・ハンドシェークで使われた 3パケットの次のパケット以降)、ACKは相手からの実電文に対する 肯定応答という意味になります。TCPでユニークなところは、 ACKパケットを単独で返すだけではなく、自分が送信する電文のTCPヘッダに、 「前回のそちらからの電文を正常に受信しました」という意味のACKビット を立てるということです。つまり、肯定応答と電文の送信を1パケットで 行うことができるということです。

    TCPでは電文を送信するたびに、送信側はシーケンス番号 (TCPパケット・ヘッダの5バイト目) を増やしてゆき、ACK は相手側から受信した「シーケンス番号」番目の バイトまでは正常に受信したことを相手側に知らせます。 また、電文に区切りがないので(論理的には)以下のようなことができます。

    スライディング・ウィンドウ
    送信側受信側説明
    送信
    データ
    送信
    バイト数
    シーケンス
    番号
    ACK
    ビット
    ACK
    番号
    パケット1 800 0
    パケット2 1000 800
    ACK800パケット1受信OK
    パケット3500 1800
    ACK1600パケット2の途中まで
    (全部で1600バイト分)受信OK
    ACK2300パケット2の後半から
    パケット3まで受信OK

    ★読者の方から、記述がやや不正確であるとのご指摘を受けましたので、 その方のご指摘をそのままの形で追加しておきます。ご指摘いただいた方、 どうもありがとうございました。

    TCPにおけるACK番号とは、 「ACKを発行した側が次に相手から受け取りを期待するデータのシーケンス番号」 です。例えば、100バイトのデータをシーケンス番号0番から送信するとすると、 このセグメントで消費されるシーケンス番号は0から99番ですよね。 そうすると受信側は、次に送られてくるセグメントに期待するシーケンス番号 である100番をACK番号として返すわけです。したがってACK番号は、相手側から 受信した(シーケンス番号-1)番目のバイトまでは正常に受信したことを相手側に 知らせます。
  4. 到着順序保証

    上記のシーケンスで見たように、受信側では、ストリームのうち 何バイト目までを受信したかを意識してACK番号をセットしてACKを返し、 データが途中で抜けた場合はそれ以降のACKを返しません。これにより、 アプリケーションから見ると到着順序が保証されます (データ抜けが発生しない)。

    送信側ではパケットを送出するたびにタイマーを発生させ、 一定時間にACKが返らないと、データの再送を行います。また、 (途中のルータによる再送などで)重複したパケットが到着する場合も ありますが、この場合はパケット・ヘッダのシーケンス番号がすべて 同一になるので、受信側はシーケンス番号(+データ長)を見て、 自分がすでにACKを返した分のデータ・ストリームは無視(破棄)します。

  5. フロー制御

    フロー制御とは、受信側が受信データの処理が追いつかなくなったとき、送信側に対してのデータ転送の中止/再開を指示することです。このしくみがないと、データ抜けなどを起こしてしまいます。

    シリアル通信など使われるフロー制御としては、XON/XOFFという文字を使って行うソフトウェア・フロー制御と、モデムの信号線をオンオフすることによって行うハードウェア・フロー制御というものがあります。

    TCPレベルで行われるフロー制御は、TCPヘッダ内のウィンドウというフィールドで行われます。ウィンドウは、受信側のバッファサイズの残りバイト数と思えばいいです。これが0で送られたということは、受信側のバッファにまだ処理していない(上位に渡していない)データが溜まりすぎて空きがなくなってしまったことを示します。ウィンドウが0の間は、送信側は(ACKを返すなどのために)TCPパケット自体は送信しますが、実データ部は送りません。しかし、送信側データはTCP/IPスタック上にあるバッファに溜められていますので、アプリケーションの送信動作がすぐに停止してしまうということはありません。