TCP/IPのうち、「信頼性のある通信」を実現するTCPについて解説。広く利用されているTCPだが、その通信の仕組みは?
「TCP/IP(Transmission Control Protocol/Internet Protocol)」は、コンピュータやアプリケーション同士の通信のために、現在最も多く使われている基幹ネットワークプロトコルである。本記事ではTCP/IPを構成するプロトコルのうち、TCPについて解説しておく。
Webサーバとブラウザ、メールサーバとメールクライアント、Webアプリケーションとスマホのアプリなど、インターネット上で利用されているほとんどのアプリケーションは、このTCPによる通信を利用している。
「TCP(Transmission Control Protocol)」は2つのアプリケーション間で、「信頼性のあるストリーム型の通信」を行うためのプロトコルである。
「信頼性のある通信」とは、送信したデータが送信した順番で正しく相手にまで届くことが保証され、何らかの理由で送信が失敗した場合には自動的に再送信するなどして、確実に相手にデータが届くことを保証する通信のことである。
送信したデータが送った通りに相手に届くのは当たり前と思うかもしれないが、実際はそうではない。ネットワークが混雑していると、例えば次のようなトラブルが生じがちだ。
このような状況を検出し、必要ならデータの並べ替えや再送処理を行って、正しいデータを相手に届けるのが「信頼性のある通信」である。またネットワークの構造や媒体、帯域幅、遅延時間などに依存せず、どのような構成でも同じように利用できることが求められている。
TCPの機能や特徴は次の通りだ。
TCPで通信をするためには、通信相手のIPアドレスとポート番号(ポート番号は16bitの整数値)を指定してサーバに接続要求を開始する。例えば、Webサーバとの通信に使われるHTTPでは、TCPの80番か443番(暗号化する場合)のポートを使って通信する(サーバ側のTCPのポート番号はアプリケーションごとにほぼ決まっている)。
これを図にすると次のようになる。
TCPの動作を確認するには、Telnetなどを使って接続先のサーバとポート番号を指定して接続してみるとよい。
TCPでは、下位のプロトコルやネットワークとして、IPや「イーサネット」、無線LANなどを利用している。これらはベストエフォート(最善努力)型であり、送信した相手にデータが必ず届くという保証はない。ネットワークが混雑していると、大幅に遅延したり、場合によっては途中で破棄されてしまう。
そんな特性のネットワーク上でも信頼性のある通信を実現するために、TCPではデータを送信するたびに必ず「確認応答(ACK:Acknowledge)を返信する」という手法を使っている。相手にデータを送信後、相手から必ずACKが返ってくるのを待ち、もし返ってこない場合は再度データを送り直す。
TCPで送信するデータの順番や並びは「シーケンス番号」という32bitの整数値で管理されている。例えば「シーケンス番号12345から2000bytes分」というフラグを付けてデータを送信する。すると受信した側では「シーケンス番号12345から1000bytes分受け取り完了。次は13345から受信」というふうに確認応答を返す。この場合は半分しか届いていないようなので、「13345から1000bytes分」を再送信することになる。そして「14344まで受信完了」というACKが返ってくれば送信は完了となる。
確認応答を使うことにより、確実な通信を実現できるが、これだけでは非常に効率の悪い通信しかできない。例えばネットワークの遅延が大きくて、パケットが1往復するのに100ミリ秒程度かかるサイトがあるとする(日本から海外へ接続する場合などに相当)。1KB程度のパケットを1つ送るたびに確認応答を1つ待つとすると、1秒で10パケット分しか送信できない(≒約10KB/s)。たとえ回線速度が100Gbit/sあったとしても、この速度しか出ない。
これでは効率が悪過ぎるので、TCPでは「ウィンドウ制御」を採用して、効率向上や輻輳(ふくそう)制御(混雑時の送信抑制制御)などを行っている。これは、ある程度の量のデータ(パケット)をまとめて送信し、それに対して受信確認を1つだけ送るという方式である。一度に受け取り可能な最大量を「受信ウィンドウサイズ」という。
例えばウィンドウサイズを1MBにすると、最大で1MB×10となり、約10MB/sで送信できることになる(TCPを1コネクションしか使わない場合)。このように、ウィンドウ制御は通信回線を効率よく使うには必須の技術である。
TCPのウィンドウサイズは通信状態によって動的に変わる。もっとパフォーマンスを上げたい場合はサイズを大きくするし、受信側の処理が追いつかなかったりリソースが不足したりしている場合は、もっと小さくして送信を一時的に待ってもらう、といった制御もする。
TCPではコネクション(接続)ごとに、それぞれシーケンス番号やACK番号、オープン/クローズなどの状態といった内部的な「ステート(状態)」を持っている。TCP接続のオープンやクローズ、確立などに伴って、次の図のように状態が変わる。
この図の最初の部分にあるオープン処理時のパケットの流れを図にすると次のようになる。
オープンしようとしている側からTCPの接続要求(SYN)を送信すると、待ち受けしている側(パッシブオープン側)はSYNに対する確認応答(ACK)を送信する。と同時に、自分の側からも相手に対してSYNを送信する。受け取った側では、そのSYNに対するACKを送信して、オープン処理が完了する。双方からSYNを送るのは、TCPが全二重の通信路だからだ。
オープン処理ではこのように3回パケットが往復するだけだが、クローズの場合は、どちらから先にクローズ要求を出すかで処理が変わり、もう少し複雑になる。
このように、TCPはプロトコルスタック内部に状態を持っているし、受信ウィンドウ用のバッファも持たなければならないなど、割と「重い」処理が必要なプロトコルである。
TCPは受信確認やウィンドウ制御などを使って信頼性のある通信を実現しているが、そのために処理が重くなっているし、特に混雑したネットワークではリアルタイム性などが損なわれることもある。現在のネットワーク技術はTCP/IPの誕生時よりもはるかに高速化・複雑化しているが、それらに対応するべく、TCPの仕様や実装方法の改良なども続けられてきた(例えば当初のTCPでは、ウィンドウサイズは最大64KBまでだった。これは現在の高速ネットワークでは小さ過ぎる)。今後もTCPの重要性は変わらないだろう。
■関連リンク
Copyright© Digital Advantage Corp. All Rights Reserved.