TCPとUDPの違いを10個挙げてみる

ふと思い立って、こんなことを考えてみた。8個くらいまではすいすい出てきたけど、10個見つけるのに意外と時間がかかった。もっとあると思うけど。

受信確認とパケット再送

おそらく、一番の違いはこれ。TCPは確実に届くがUDPはそうではないと言われる所以。

速度

これもTCPとUDPを大きく分ける理由の一つ。上記の受信確認もそうだが、TCPは様々な制御を行っているため、通信速度はUDPよりも遅い。そこで、不確実でもデータを高速に送りたい場合はUDPを採用することが多い。また、TCPの過剰な機能が環境によっては不都合なことがあり、その場合はUDPベースで独自プロトコルを実装することがある。

順序保証

TCPにはシーケンス番号があるので、同一ストリームで複数のメッセージを送った際には、その順番が保証される。例えば、"hoge"の後に"fuga"を送信した場合、TCPでは確実に"hoge" "fuga"の順で受信側がデータを読み取る。しかしUDPでは、場合によっては"fuga"が先に届き、処理されてしまうかもしれない。

輻輳制御

TCPにはウィンドウサイズやスロースタートなど輻輳制御用の機能がある。UDPにはないので、好き勝手にパケットを送っていると、ネットワークや経路上の機器に負荷をかけることになる。
ただしTCPの輻輳制御技術は、インターネットのように帯域幅の割にRTTの長い地域との通信がある場合、通信速度の低下の原因にもなる。

状態遷移

TCPには状態遷移があり、通信しているのかしていないのかが判別できる。これはTCPヘッダから分かるので、中間のNATやFirewallなどもこの状態を判別できる。UDPにはこれがないので、通信開始のパケットなのか、途中のパケットなのか、または通信が終わったのか、それとも長い待ち状態に入っただけなのかが分からない。逆にパケットが状態や方向性を持たないので、NATを越えてP2P通信することも出来たりする。(UDP Hole Punching)

MTUに応じたパケット分割

TCPはMTUに応じたパケット分割を行うことで、IPフラグメンテーションを防ぐ。これにより、フラグメントされたパケットの一部がロスした場合の再送コストを下げることができるし、パケット分割や再構築の負荷を減らすことができる。

TCP=ストリーム指向、UDP=メッセージ指向

TCPはオリジナルのメッセージとは異なるところでパケットを分割する。そのため受信側としてはTCPパケットのどこが元のメッセージの分割点だったのかが分からない。例えば "hoge" "fuga" を送る場合に、TCPレイヤーで "ho" "ge" "fu" "ga" と4つのTCPパケットに分割されてしまうと、受信側では分割前の状態を確認する手段がない*1UDPはこの分割を行わないので、受信側もメッセージの固まりを認識することができる。

マルチキャスト

マルチキャストする場合は、UDPを利用する。

スプーフィング耐性

IPパケットはIPアドレス部分の詐称が可能なので、第三者がIPアドレスを偽ったパケットを送信し、通信に割り込むことができる(IPスプーフィング)。これによって、セキュリティ上の問題が発生する。TCPにはシーケンス番号があるので、初期値として第三者に推測しづらいようにランダムな数値が割り当てることで、この割り込みを発生しづらくできる。一方UDPにはそういったものがないため、上位レイヤーで問題のあるパケットを識別しなければならない。

拡張性

TCPヘッダーにはオプション領域があり、各種拡張に使用されているが、UDPにはない。(UDPはポート番号、パケット長、チェックサムのみ。)
TCPオプションの使われ方としては、MSSの通知、ウィンドウスケーリング、Selective ACK、TCPタイムスタンプ(RTTの計測と再送時間の最適化用)など。

*1:もちろん、こんな小さな単位で分割されることはないけど