3

バックグラウンド

Linux カーネル 2.6.35 を実行する小さなヘッドレス ボックスと、ARM ハードウェア上の Open Embedded ディストリビューションのいくつかのバリアントがあります。

私たちが知る限り、glibc 2.10.1 を使用しています。

ボックスには、接続されていないイーサネットと、シリアル接続された GSM/3G モデムがあります。インターネットへの接続を継続できるように PPP を構成しました。この部分は問題なく動作します。

ソケットを使用して何らかの接続を行う c (実際には c++) でコーディングされたプログラムがあります。このプログラムは、pthreads を使用して高度にマルチスレッド化されています。

接続先の IP アドレスを検索するには、gethostbyname() を使用します。

インターネットへの接続がない場合、たとえば初期ブート中または SIM カードがモデムから取り外された場合、gethostbyname() は本来あるべき NULL を返します。

症状

しかし、インターネット接続が稼働しているにもかかわらず、時折 gethostbyname() が NULL を返し続けます。

getaddrinfo() を使用した場合のエラー コードは EAI_NONAME ~ "名前またはサービスが不明です" です。gethostbyname() からのエラー コードは手元にありませんが、同等でした。

私たちの分析

(シリアルコンソール経由で)インターネット接続が正常であることを確認しました

  • リスト項目
  • /var/log/messages を確認し、pppd がすべて OK であることを確認しました
  • ホスト名を ping します (IP に変換され、OK と応答します)
  • パブリック IP 経由で ssh 経由でボックスに接続します

プロセスには、同じホストに対して gethostbyname() を使用する 2 つのスレッドがあります。コードパスと関数はわずかに異なりますが、gethostbyname() を呼び出す部分を含め、ソケット関数に共通のコードを使用します。

gethostbyname() が NULL を返し続ける状況では、これは通常、スレッドの 1 つにのみ当てはまり、毎回同じスレッドではありません。もう1つはルックアップを完全に行います。

さらに、失敗した gethostbyname() を持つスレッドは、そのスレッドを簡単に制御して停止し、関数を再起動することで簡単に機能させることができます。これにより、新しいスレッドが pthread 単位で生成されます。

全体として、DNS 変換とインターネット接続が OS レベルで正常に機能していると確信しています。

スレッド化の問題を排除するために、マニュアル ページに従って再入可能である getaddrinfo() を使用してルックアップ コードを再実装しました。そして、まったく同じ結果が得られます。

スレッドを終了すると、gethostbyname()/getaddrinfo() のルックアップ機能に影響を与えるある種のクリーンアップが発生するようです。

回避策は、失敗したスレッドを強制的に終了させることですが、これはアプリケーション構造の大幅な変更を意味し、実際にはオプションではありません。

質問

質問は次のとおりです。解決策を探す場所や、実際の問題がどこにあるのか、何かヒントはありますか?

4

1 に答える 1

-3
    char *hostname = "www.example.com";
    struct hostent *a_server;
    a_server=gethostbyname(hostname);
    while (a_server == NULL) {
            a_server=gethostbyname(hostname);
            sleep(1);
    }
于 2016-08-23T09:39:34.530 に答える