LoginSignup
1
0

More than 1 year has passed since last update.

UDP/IP通信を選択するときのチェックリスト

Last updated at Posted at 2022-02-27

とある案件で、アプリケーション間の通信にUDPを使う検討をした時のメモ。
一般的な「Ethernet」の上で動く前提で書きます。

用語の定義

この記事では、以下の定義で用語を使用します。

  • IPパケット
    IP(Internet Protocol)層でやり取りされるパケットで、IPヘッダおよびデータ部分で構成されるもの。
    この記事では、「MTU単位で分割されたデータ」という意味で使用する。

  • MTU(Maximum Transmission Unit)
    一度に送信することができるデータのサイズ。
    物理的なネットワーク媒体ごとに固有の値を持っている(イーサネットであれば最大1500bytes)。

  • UDPパケット
    UDP(User Datagram Protocol)層でやり取りされるパケットで、UDPヘッダおよびデータ部分で構成されるもの。

前提知識:各レイヤーにおける「データの信頼性」

イーサネット

フレームチェックシーケンスにより、受信側でフレーム内の破損検出を行う。
フレームが破損していた場合、そのフレームは破棄される。

IP

IPプロトコル自身は、IPパケットの消失、複製、順序の入れ替わりが起こりうる。が、これを救う仕組みはない(上位プロトコルの実装次第)。
IPパケットのヘッダには「チェックサム」があり、チェックサムが合わないIPパケットはルーティング中に破棄される。
(つまり、受信したIPパケット自身は正しい)

(参考)TCP

ネットワーク層以下のパケット転送は信頼できないという考えのもと、信頼性を保証するための機構が準備されている。

  • 確認応答
    受信側は、パケットを受信したときに「受信したこと」を送信側に応答する。
    この応答を送信側で受け取らなかったときは、パケット紛失と判断して再送する。

  • フロー制御
    確認応答で、受信側バッファーの空きサイズを通知する。
    送信側は、空きがあると分かったときにパケットを送信する。

  • 順序制御
    上位層から受け取ったデータが(厳密には、データにTCPヘッダ、IPヘッダを付与したものが)MTUより大きい場合、TCPで分割を行う。
    分割時に「シーケンス番号」を書き込み、受信側でデータを組み立てるときにシーケンス番号を用いる。
    IPプロトコルでも分割する仕掛けはある(IPフラグメンテーション)が、IPプロトコルでは組み立て時の順序性の保証はしないため、TCPが肩代わりする。

  • 輻輳制御
    分割したデータ(TCPセグメント)が紛失したとき、上記の仕組みで再送を行う。
    再送が頻発する状態になったとき、送信するデータ数を制限して、輻輳が連続して発生しないようにする。

UDP

TCPのような信頼性機構は持たない。

UDP/IP通信を選択するときのチェックリスト

  • 多少のメッセージ抜けは許されるか?
    (例)
     ・xx秒おきにデータを送る仕様なので、1、2回の抜けであれば許容できる
     ・受信するアプリケーション側(もしくはUDPよりも上位のレイヤー)で、データが抜けてもスキップする仕掛けがある1
     ・ダメだった場合はユーザーがリトライすればよい2
    →許されないならば、TCPを使ったほうが楽だと思います。
  • UDPの特性がアプリケーションにとって好ましいか?
    (例)
     ・マルチキャスト送信で、データ転送量を削減したい
     ・TCPの信頼性機構が逆に邪魔
      (タイムアウト・リトライなどを悠長にしている場合じゃない/挙動に影響されたくない、など。)
     ・TCPのプロトコルオーバーヘッドが気になるほど能にシビア
      (DNSなどがそうらしい3。)
    →こういった前向きな理由があるならば、ぜひUDPを検討しましょう。
     ただ、性能にシビアなアプリケーションを作るならば、有識者と入念に設計レビューしましょう。
  • 通信路は安定しているか?
    IPパケットの紛失が頻繁に発生するような通信路で、データサイズがMTUに収まらないようなメッセージを送るのには不向きといえるでしょう4
    (後述する「データがMTUに収まらない」レベルのデータを送る場合、すべてのIPパケットが揃わないとメッセージは不正になり、破棄せざるを得ないため。)
    →「閉域のイーサネットでイマドキのL2/L3スイッチを使っていれば大丈夫」と聞くが、実際どうなのかは不明(詳しく調べたい)
  • 送信するデータ量はどれくらいか?
    • データが(UDPヘッダ、IPヘッダを含めても)MTUに収まる(1472bytes以下5
      1つのIPパケットに収まるため、データの部分的な消失、データ内の順序の入れ替わりは気にしなくてよい。
      ただし、複数の同じデータが到達する可能性はあるため、複数のUDPパケットが到達しても問題ない、または後着を破棄するアプリケーションの設計が必要
      (2022/02/28追記) もちろん、データが到達しない可能性の考慮は必要。

    • 上記よりも大きいデータサイズ
      (2022/02/28訂正ここから)
      メッセージは複数のIPパケットに分割される。そのため、IPパケットの紛失、複製、順序の入れ替わりを考慮した設計が必要。
      具体的には、受信側で「メッセージのサイズ、ハッシュなど」を確認するなど。
      ※上記設計であれば、もしUDP受信バッファを超えるUDPパケットが来た場合も検知できる。その他、LinuxのsocketであればMSG_TRUNCフラグ6を見るなど。

      IPフラグメントの再構築時は、IPプロトコルにて再構築が行われる。すべてのIPパケットが揃うまで上位層には渡されない(そのままタイムアウトする)。7
      そのため、UDPパケットとして受信できているならば、構成するIPパケットの紛失や複製、順序の入れ替わりは考慮不要。
      (一応UDPでも、UDPヘッダにチェックサムを入れることはできる。ただし、IPv4はオプション扱いとのこと。8
      「データがMTUに収まる」のケースと同様に、複数のデータが到達した場合、データが到達しなかった場合を考慮したアプリケーションの設計は必要。
      (2022/02/28訂正ここまで)

    • Wikipediaでも言及しているとおり9、送信データが大容量の場合は転送レートを下げるなどの設計が必要(輻輳制御にあたるもの)。

    • 連続してUDPパケットを送信する場合、受信側でデータ受信~処理を行える十分な時間間隔をあけるなどの設計が必要(フロー制御にあたるもの)。

全体的に読んでおきたいWebサイト

こちらも参考にさせていただきました。

  1. よくUDPの例に出てくるVoIPの場合、UDPの上位にRTP(Real-time Transport Protocol)があり、その時刻情報からデータ順序を把握する。

  2. Wake on LANなんかがこれに該当する。

  3. https://atmarkit.itmedia.co.jp/fnetwork/dnstips/028.html

  4. 数学は何十年前に投げ捨てたのであっているかわからないですが、それっぽく書くと
    通信路でIPパケットが紛失する確率をP(Pは0以上1以下)、分割数をnとすると
     メッセージが届かない確率=(1-P)^n
    となる、はず。

  5. https://blogs.itmedia.co.jp/komata/2011/04/udp-8fa9.html

  6. https://linuxjm.osdn.jp/html/LDP_man-pages/man7/udp.7.html

  7. https://atmarkit.itmedia.co.jp/ait/articles/0304/04/news001_3.html

  8. http://www.ieice-hbkb.org/files/03/03gun_04hen_04.pdf

  9. https://ja.wikipedia.org/wiki/User_Datagram_Protocol#%E4%BF%A1%E9%A0%BC%E6%80%A7%E3%81%A8%E8%BC%BB%E8%BC%B3%E5%88%B6%E5%BE%A1%E3%81%AE%E5%AE%9F%E7%8F%BE

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0