« タカチのMS88ケースの設計のコツ | トップページ | WindowsでTCP/IPのプログラムを作ったときに名前解決を早くする »

2021.09.09

WindowsでTCP/IPのプログラムを作ったときに名前解決が遅い

ZYNQで組み込みシステムを作って、Windowsで作ったプログラムからネットワーク経由でコントロールしたい場合に、アプリを作ることになりますがが、ホスト名の名前解決で1秒くらい待たされる現象が起きていました。

状況としては、

  • ターゲットはZYNQ(ARM)で動作するLinuxの組み込みシステム。Ubuntu 18.04LTS。IPv6有効
  • ターゲットLinuxでは、mDNS用にavahi-daemon、NetBIOS用にnmbdを実行
  • ホストPCはWindows 10
  • ホストとターゲットは同一ネットワークの有線LANで、遅延は極めて少ない
  • DNSサーバは立てていない

です。

こういう環境で、Windowsのプログラムから組み込みLinuxをネットワーク越しでコントロールしようとすると、プログラムの起動時に名前解決で1秒ほど固まってしまうのです。

 

TCP/IPのプログラムを作る際に、ホスト名をIPアドレスに変換する名前解決にはgetaddrinfo()を使いますが、Visual Studioのデバッガでステップ実行してみるとgetaddrinfo()で1秒ほど待たされていることがわかりました。

このgetaddrinfo()は、"cszmini"みたいなホスト名から192.168.1.12のようなIPアドレスに変換してくれます。

Getaddrinfo

getaddrinfo()はプログラムの起動時に必ず実行するので、1秒間ひっかかるような動作をしてしまいます。

 

自作プログラムの固まる箇所はgetaddrinfo()にあることがわかったのですが、どうやら普通にpingを打つだけでも同様に最初に1秒間固まることがわかってきました。

しかしながらpingで固まるのは最初のICMPの送信が始まる前なので、PINGの遅延時間に表示されません。

Ping

おそらくPINGというシステムツールも、中ではgetaddrinfo()を呼び出しているのでしょう。getaddrinfo()のほかにGetAddrInfoEx()というAPI関数もあるのですが、結果は同じでした。要するにWindowsの名前解決では、ローカルネットワークで隣にある機械の名前解決に必ず1秒待たされるのです。

MS-DOSプロンプトを開いてping cszminiと打って、Wiresharkでパケットをキャプチャして調べてみると、DNS、mDNS、NETBIOSと3つの方法で調べていることがわかります。

Dns

上のパケットで何が起きているかを説明しますと、

  • WindowsからデフォルトゲートウェイにDNSで「cszmini.ドメイン」を知らないかを問い合わせ
  • ローカルのネットワークにIPv4のMDNSで「cszmini.local」のホストがいないかをAレコード(IPv4)問い合わせ
  • ローカルのネットワークにIPv6のMDNSで「cszmini.local」のホストがいないかをAレコード(IPv4)問い合わせ
  • ローカルのネットワークにIPv4のMDNSで「cszmini.local」のホストがいないかをAAAAレコード(IPv6)問い合わせ
  • 192.168.1.12のターゲットからレスポンスあり
  • デフォルトゲートウェイから「cszmini.ドメイン」という名前のホストは、ネットワークの外にはないと返事
  • NetBIOSでCSZMINIがいないか問い合わせ
  • 再びローカルのネットワークにIPv4とIPv6のMDNSで「cszmini.local」のホストがいないかをAレコード(IPv4)およびAAAAレコード(IPv6アドレス)問い合わせ
  • NetBIOSでの返事あり
  • 再びローカルのネットワークにIPv4とIPv6のMDNSで「cszmini.local」のホストがいないかをAレコード(IPv4)およびAAAAレコード(IPv6アドレス)問い合わせ
  • MDNSでの返事あり

という感じでした。PINGを起動したときから名前解決が走っているのですが、このプロセスが終了するまでに1.03秒かかっていることがわかります。しかもMDNSではすぐにAレコードとAAAAレコードを返している(17番と19番)のですが、Windowsはこれを無視してしまっています。

上の過程では、デフォルトゲートウェイに向けてDNSを送っていてわかりにくいので、DNSとPINGに絞ってみます。

Windowspingpacket_20210912002101

PING開始時にMDNSを使って「cszmini.local」がいないかどうかを調べているのですが、1.37秒付近で名前解決を開始して、実際にPINGが飛んでいるのは2.39秒なので、名前解決で1.02秒待っていることがわかります。おそらく、MDNSのタイムアウトが1秒になっているのでしょう。

このようにターゲット機器がMDNSでホスト名を返しているし、NetBIOSでもホスト名を返しているのですが、Windowsのgetaddrinfo()は1秒ほど待つようになっていて、極めて体感速度が遅く感じられてしまうのです。

続く

|

« タカチのMS88ケースの設計のコツ | トップページ | WindowsでTCP/IPのプログラムを作ったときに名前解決を早くする »

コメント

コメントを書く



(ウェブ上には掲載しません)




« タカチのMS88ケースの設計のコツ | トップページ | WindowsでTCP/IPのプログラムを作ったときに名前解決を早くする »