2015-05-20 108 views
5

我正在編寫一個C應用程序,它在啓動時作爲systemd service運行,並且應該連接到服務器。因爲應用程序在啓動時運行,所以最終會發生網絡連接尚未建立。這自然會導致第一個功能失敗,這需要一個,在我的情況下是getaddrinfo如果getaddrinfo一旦失敗(即使在網絡準備就緒後)失敗

所以我想我只會寫一個循環,它會反覆調用getaddrinfo,直到網絡準備好後纔會結束。不幸的是,我發現getaddrinfo即使在連接建立之後仍然與name or service not known一起失敗。

我能夠通過主機名ping服務器,但getaddrinfo仍然不會這樣做。如果我停止應用程序並再次運行它,一切正常。如果網絡連接在第一次通話之前已經建立,則getaddrinfo也可以正常工作。

顯然,如果getaddrinfo因爲網絡未準備好而失敗一次,它將永遠失敗。似乎沒有意識到現有的連接。在使用已棄用的gethostbyname時,行爲是相同的。

這種行爲的原因是什麼?有沒有辦法強制getaddrinfo刷新內部變量(如果存在的話)或類似的東西,這可能解釋爲什麼該函數仍然認爲沒有連接?是否還有另一個功能,我應該先調用以檢查網絡是否準備就緒?

我想避免延遲等待一段時間,期待網絡連接後。我也希望檢查從我的應用程序中的連接,並沒有一個bash腳本首先檢查它,然後啓動應用程序。

回答

4

您可以通過編譯下面的測試程序,並按照以下說明理解答案:

#include <sys/types.h> 
#include <sys/socket.h> 
#include <netdb.h> 
#include <stdio.h> 
#include <unistd.h> 

int main(int argc, char *argv[]) 
{ 
    while (1) 
    { 
     struct addrinfo *res; 
     int rc=getaddrinfo(argv[1], "http", NULL, &res); 

     printf("getaddrinfo returned %d\n", rc); 

     if (rc == 0) 
      freeaddrinfo(res); 

     sleep(1); 
    } 
} 

在運行這個測試程序:

  1. 連接到網絡。
  2. 重命名,臨時/etc/resolv.conf/etc/resolv.conf.save
  3. 使用良好的主機名啓動此測試程序。
  4. 測試程序啓動後不久,開始打印錯誤代碼,請將/etc/resolv.conf.save重命名爲/etc/resolv.conf
  5. 注意到測試程序仍在報告DNS解析失敗。
  6. 但是,如果您使用CTRL-C並重新啓動它,測試程序現在將報告有效的DNS解析。

當您從網絡斷開連接並重新連接時,網絡堆棧會相應地重寫和更新/etc/resolv.conf。 C庫中的DNS解析器需要此配置文件。 C庫首次從/etc/resolv.conf中讀取DNS配置,並對其進行緩存。如果/etc/resolv.conf的內容發生變化,它不會檢查每個查詢。

最後:

  • 你的家庭作業是添加到res_init()一個電話,在resolv.h定義,這個測試程序,讀取相應的手冊頁,看看會發生什麼。這是你的答案。
  • +0

    由此,我的意思是res_init()在循環內。 –

    +0

    這實際上有時(但很少)有效。我假設它在網絡連接已經建立的情況下工作,但是當應用程序啓動時'resolv.conf'尚未更新。一旦'resolv.conf'被更新,在循環中對'res_init'的調用加載新的配置,然後'getaddrinfo'結束。 但是,如果網絡連接在應用程序啓動時尚未準備好,它仍然保持失敗, – kassiopeia

    +0

    我的分步演示涉及在完全沒有配置DNS解析時啓動應用程序,這種情況在沒有網絡連接時就會出現。您是否嘗試在沒有網絡連接的情況下調用rs_init()來啓動演示代碼,然後連接到網絡?這個簡短的小演示代碼很容易測試。沒有必要承擔任何事情。 –