TCPとは
TCP(Transmission Control Protocol)とはネットワーク通信で使われるプロトコルの1つです。主にウェブ閲覧やメール、ファイル転送などデータ通信の場面で使用されます。
特徴|信頼性の高い通信をする
TCPの特徴として信頼性の高さがあります。この信頼性とは
「データを壊さずに確実に届ける」
ということの可能性が高められるという意味です。ではどのようにして信頼性を高めているのでしょうか?
通信開始前の準備|ソケット
通信を開始する前にソケットというものを準備します。サーバ側はサーバソフトを立ち上げたタイミングでソケットが生成されます。クライアント側はアプリケーションがサーバに接続するタイミングで生成されるのが一般的とのことでした。
スリーウェイハンドシェイク|通信開始時
まず通信を開始する前に通信ができるかを確認するプロセス(仕組み)がTCP通信では整備されています。では具体的にどのような手順を踏むのかみてみましょう。
通信開始時の手続き
通信の開始は以下の手順で行います。
1.クライアントPCからサーバに「通信したいです」という意味でSYNパケットを送信します。SYNはsynchronizeで同期するという意味になります。ちなみにこの時、送信元のクライアントPCのポート番号とサーバ側のポート番号をTCPヘッダに含めて送信します。こうすることでソケット同士が接続されるよう準備をしています。
2.サーバからクライアントPCに「OKです!通信しましょう!」という意味でSYN-ACKパケットを送信します。ACKはacknowledgeの略で認めるという意味です。
3.再度クライアントPCから「では通信しますね!」という意味でACKパケットを送信します。(2で送られてきたTCPヘッダを確認してSYNが1になっていれば接続成功なのでそれを確認してからACKパケットを送信する流れになります)
これで通信開始の準備が整いスリーウェイハンドシェイクのプロセスが終了しました。スリーウェイハンドシェイクが終了したらコネクション(接続やセッションとも言います)が確立できたので制御をアプリケーションに戻します。
SYN/ACKとは
ここで出てきたSYNパケットやACKパケットとは具体的にどんなパケットなのでしょうか?答えはTCPヘッダのコントロールビットフィールドにSYNやACKと指定されたパケットのことを言います。コントロールパケットの範囲は6ビット確保されていますが、これらを指定するのに1ビットで事足りるためSYN-ACKパケットにおいても1つのパケットで2ビットを使い送信されるとのことでした。ちなみにこのスリーウェイハンドシェイクの際はボディ(ペイロード)部分は空で送信されるようです。
パケットごとの伝送確認も行う
データはパケットと呼ばれる小包のような形で小分けにして送信されるのですが、ある程度の範囲を決めてその都度確認をします。1000バイトごとにデータを送信する場合は1~1000バイトでちゃんと届きましたか?という確認をしてから次の1001バイト〜2000バイトのデータを送信します。この時クライアントPCからはシーケンス番号がサーバへ送信され、その応答としてサーバからクライアントPCへACK番号というものが発行されます。これにより通信が失敗したらそこで失敗したことがわかるような仕組みになっているんですね。
パケットの送信失敗
パケットのデータが壊れてしまったり、届かなかったりということもあります。
その際はACKの応答がないのでしばらく待ってもない場合は再度同じデータを送信します。
ACK番号の送信失敗
反対にデータがサーバに届いたんだけれどもその応答としてのACK番号が通信の途中で喪失してしまうこともあります。こちらも同様にクライアントPCから見れば応答がないということになるので再度同じデータを送信する形になります。
フォーハンドシェイク|通信終了時
TCPは通信終了時も慎重に確認を行います。このプロセスをフォーハンドシェイクと呼びます。
1.クライアントPCからサーバへ「通信を終了したいです」という意味でFINパケットを送信します。
2.サーバからクライアントPCへ「OKです」という意味でACKパケットを送信します。
3.サーバからクライアントPCへ「通信を終了したいです」という意味でFINパケットを送信します。
4.クライアントPCからサーバへ「OKです」という意味でACKパケットを送信します。
スリーハンドシェイク|通信終了時
書籍によっては終了時もスリーハンドシェイクと説明されているものがあります。これは前述のフォーハンドシェイクの手順2と3を一気に説明しています。重要なのはクライアントPCからとサーバからと独立して終了確認をしているというところなのでそこをしっかり押さえておきましょう。
サーバ側から終了フェーズが始まる場合もある
前述のクライアントから終了フェーズが始まる流れは説明でよく使われるパターンなのですが、実はアプリケーションや状況によってはサーバ側から終了フェーズが始まるケースもあります。
ソケットの削除
通信終了フェーズが完了したらソケットが削除されます。
TCPが持っている機能
再送制御
パケットが消失した際に再送を行います。
これはTCPヘッダにあるシーケンス番号とACK番号を用いて判断します。特定のシーケンス番号が抜けている場合も検出して再送を試みますが、一定時間エラーが出た場合は通信そのものを遮断します。
順序制御
パケットの順番が入れ替わった際に調整します。
これもTCPヘッダのシーケンス番号を元に組み立てます。
コネクション制御
通信相手がいるかどうかを確認してから通信します。
パケット量制御(実際に制御を行うのはOSのプロトコルスタックやアプリ)
ネットワークがふくそう状態にならないように調整しながら通信します。
具体的には連続してパケットを送信する際に、プロトコルスタックが持つバッファメモリ領域にデータを溜めて一定時間ずつ送信するという機能があります。これはデータを溜めすぎても、溜めなさすぎても通信速度やネットワークリソースに無駄が生じてしまうので理想的には適切なタイミングで送信できれば良いとされています。しかし、TCPプロトコルの仕様ではこの制御に関する規定がなく、プロトコルスタックの開発者、アプリケーションの開発者がコントロールできるようになっています。ちなみにブラウザのような会話型のアプリケーションでサーバに送信する際はバッファに溜めずに送信することが多いようです。
チェックサム機能
TCPのチェックサム機能は通信途中にあるルーターやメモリの故障、プログラムのバグなどによってデータが破壊されないことを保証するためだと考えられています。これらの原因でヘッダとデータが破壊されていないかどうかをチェックすることができます。
逆に通信途中のノイズによるビットのエラーはデータリンク層のFCS(Frame Check Sequence)で検出できます。
TCPがヘッダに持つ情報
TCPはさまざまな機能を持っていますがそれを実現するために必要な情報があります。それら情報はヘッダという形で数ビットを使用してパケットに組み込まれる形でクライアントサーバ間でやり取りされたりメモリ領域に保存されたりしています。以下に主な項目を挙げてみます。
ポート番号
送信元ポート番号と宛先ポート番号が格納されます。これによってソケット同士を繋げることができ通信できるようになります。
シーケンス番号
パケットは小さく分割されて送信されます。これはネットワークの帯域を効率よく使うためです。分割されたパケットは受信側で再度組み立てられるのですがこの時順番があべこべにならないようにする必要があります。その時にシーケンス番号を元に組み立てます。シーケンス番号は実際には乱数が生成されそれを基準に組み立てる形になります。これはセキュリティ強化のために乱数を使うようです。
確認応答番号|ACK番号
ACK番号は、正しく受信したデータの最後のバイトの次のバイトを指します。これによって通信が正常に受信されたか、どのシーケンスまでが届いているかなどを確認することができます。
ウィンドウサイズ
一度に送信できるデータサイズをウィンドウサイズと呼びます。一度に送信できるサイズはTCPが回線の状況を見て判断して調整します。「 パケットごとの伝送確認を行う」の項目でデータを送った後サーバからACKパケットが返信されていますがここまでがウィンドウサイズになります。
チェックサム
TCPが向いている通信
・信頼性が必要な通信(データ損失が困る場合)
・ファイル転送などインターネットを介して大量データを転送する場合
・ライブ配信、音楽配信などのストリーミング再生、これらは即時性がそれほど必要とされません。
・どのような回線でもそれなりの性能を期待する場合。(広帯域/狭帯域、高信頼/低信頼、MTU※の違いなど)※回線の太さ、一度に送ることが可能なパケットの大きさみたいなもの
TCP最大スループットの計算方法
まずはスループットとは何か確認します。
TCPにおける最大スループットとは
最大スループットとは一定時間内に送信できるデータ量のことを言います。
このことから通信速度にも関連していてスループットが高い数値であれば通信速度も速いということになります。
TCPの最大スループットの計算方法は以下のようになります。これはTCPの1コネクションで転送できる最大スループットを表しています。
ラウンドトリップ時間とは
ラウンドトリップ時間とはウィンドウのやり取りを基準に考えます。一つのウィンドウがクライアントからサーバに送信されてサーバからクライアントへACKパケットが返信されるまでの時間をラウンドトリップ時間と呼びます。
最大スループット計算例
ウィンドウが65535オクテットでラウンドトリップ時間が0.1秒の時は以下のように計算できます。
TCPの高速化手法
スライディングウィンドウ方式
これは簡単に説明すると通常のTCP通信では1~1000バイトまでのデータを送信し、次に1001~2000バイトまでのデータを送信としていたのを、「とりあえず5000バイトまでのデータを送信させてください」という形で一定のデータまではACKの応答がなくても送信してしまう方法になります。この一定のデータのことをウィンドウと呼びます。そしてウィンドウがどんどんスライドする形でデータが送信されるのでスライディングウィンドウ方式というわけですね。
高速再送制御
こちらはACKの確認を緩くして高速化する手法です。データの制限なくACKの返信を待たずにデータをどんどん送信します。そしてトラブルが起きた際は必要最小限でACKの確認を行なってデータ通信をします。
フロー制御|スロースタート
トラブルの内容として受信側のPC性能が遅いということもあります。こういった場合を想定してTCPでは前述のウィンドウサイズを小さく開始して徐々にウィンドウサイズを大きくするという手法があります。これをスロースタートと呼びます。
ここで説明しているフロー制御は通信の間の調整も続けてくれます。例えば受信側のリソースに余裕がなくなった場合はACKパケットにウィンドウを小さくするようなメッセージを添えて送信されます。
なぜTCP(信頼性の高い通信)が必要なのか?
TCPはトランスポート層のプロトコルですがその下で動いているのはネットワーク層のIPになります。そしてこのIPはベストエフォートと呼ばれる「とにかく通信する努力はするけどダメだったらダメでしょうがない」という感じの通信をします。(UDPもベストエフォートですね)それゆえそこを保管する意味でTCPが通信のチェックを行いながら確実にデータを届ける仕組みを提供しているということになります。
UDPとの比較
UDPがコネクションレスでコネクションの確認をしないのに対してTCPはコネクション(3・4ウェイハンドシェイク)をしっかり行うプロトコルです。これらの特性の違いから使用される場面も違ってきます。
UDPは総パケット数が少ない通信(DNSやSNMPなど)、LANなどの特定のネットワークに限定したアプリケーションの通信、リアルタイムでの音声通信(IP電話など)や動画通信(テレビ会議など)、ブロードキャストやマルチキャストなど同報性が必要な通信で使用されます。
対してTCPは一方向性での通信で使用されます。ファイル転送や動画のストリーミング再生などはリアルタイム性よりも信頼性が必要になるのでTCPが使用されるというわけです。ブラウザやメールなどのアプリケーションがデータを送受信する場合はTCPが使われます。
ヘッダ情報での違い
ヘッダ情報でも違いがあります。UDPはシーケンス番号がヘッダ情報にありません。これは前述したTCPのような伝送確認プロセスがUDPにはそもそもないためです。
UDPにおいてはパケットの分割はIP層でのフラグメンテーションのみが行われる形になります。
Discussion