動機
UDPを学んでいくと、何故TCPが相互的に通信ができるのか気になってきませんか?
ましてやQUICに至っては、UDPの上に作られたプロトコルのくせにKeep-Aliveが使えるってもう訳わかんなくなってくるんです。
TCPの双方向通信
TCPで双方向通信が実現できる理由は、NATの仕組みを理解すればすぐ分かるはずです。
TCPがコネクションを確立すると、NATは、LANとWANのIPアドレス:ポート
の変換テーブルを作成します。この変換テーブルは、コネクションが切断される(通信が生きていると判定されなくなる)まで残ります。
コネクションが切れると、通信が切れたと判断されて変換テーブルはすぐに削除されます。
ちなみに変換テーブルがコネクションが存在する間に置き換わってしまうと、別の場所にパケットが届くようになってしまいますww
UDPだと…
UDPは、その性質上コネクションを確立しません(これをデータグラム方式という、UDP = User Datagram Protocol)。
そのため、まずまず双方向通信するように設計されていないのです。
また、このときのNATの変換テーブルはどのタイミングで削除されるかというと…
しばらく通信がなかったとき
です。
つまり、リクエストに対してレスポンスを返すまでに時間がかかりすぎると、別の宛先にパケットが届いたり、到達できなかったりします。
しかもUDPの仕組み上、パケットが正しく届いたかどうかを知ることもできません。
それを解決するのがQUICなのだ!
これを踏まえると、QUICでは3としてKeep-Aliveが使える理由がはっきりしてきます。
その理由はズバリ!
IMPORTANT
Googleが実装したから!
え、内容うっすって?
でもこんな簡単なことが私は理解できていなかったのです。面白いですね。
- パケットが正しく届いたかどうかを確認する
- Heartbeatを送信して接続を維持する
- NATの標準ポートで通信できる
そういうのが、QUICです。UDPのダメな点を直してくれています。
HTTPの標準に合うようにUDPの上に作ったプロトコルがQUICですので、接続を確立することができます。接続を確立したあと、TCPの場合はコネクションが切れたかどうかでNATはテーブルの破棄を行いますが、QUICの場合は定期的にping用のパケットを送ることで、接続を維持します。
これでUDPでもNATが壊れないんですね!🤯
UDP単体でも双方向通信は一応できる
パケット構造とヘッダー構造的に見て、リクエスト元のIP Addressとポートは分かるので、サーバーがそこに対してUDPでデータを投げれば済む話ではある。
クライアント側に関しては、NATのテーブルが残る限り、LANからWANへの送信パケットはもちろん、WANからLANへの受信パケットも転送できる。そのため、UDPサーバーを送信と同じポートで待機すれば済む。
ちなみに送信に何のポートを使うのかはこういう感じで作れるらしい。
sock.bind(("0.0.0.0", 12345))
よく分からんね