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()はプログラムの起動時に必ず実行するので、1秒間ひっかかるような動作をしてしまいます。
自作プログラムの固まる箇所はgetaddrinfo()にあることがわかったのですが、どうやら普通にpingを打つだけでも同様に最初に1秒間固まることがわかってきました。
しかしながらpingで固まるのは最初のICMPの送信が始まる前なので、PINGの遅延時間に表示されません。
おそらくPINGというシステムツールも、中ではgetaddrinfo()を呼び出しているのでしょう。getaddrinfo()のほかにGetAddrInfoEx()というAPI関数もあるのですが、結果は同じでした。要するにWindowsの名前解決では、ローカルネットワークで隣にある機械の名前解決に必ず1秒待たされるのです。
MS-DOSプロンプトを開いてping cszminiと打って、Wiresharkでパケットをキャプチャして調べてみると、DNS、mDNS、NETBIOSと3つの方法で調べていることがわかります。
上のパケットで何が起きているかを説明しますと、
- 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に絞ってみます。
PING開始時にMDNSを使って「cszmini.local」がいないかどうかを調べているのですが、1.37秒付近で名前解決を開始して、実際にPINGが飛んでいるのは2.39秒なので、名前解決で1.02秒待っていることがわかります。おそらく、MDNSのタイムアウトが1秒になっているのでしょう。
このようにターゲット機器がMDNSでホスト名を返しているし、NetBIOSでもホスト名を返しているのですが、Windowsのgetaddrinfo()は1秒ほど待つようになっていて、極めて体感速度が遅く感じられてしまうのです。
| 固定リンク
コメント