Linux

啟動時呼叫 getaddrinfo() 的程序永久卡在錯誤的 /etc/resolv.conf 中?

  • September 13, 2013

我正在pianod使用 Arch Linux ARM 的 Raspberry Pi 上執行 Pandora 客戶端/伺服器。我已pianod設置為在啟動時作為服務執行。它在網路堆棧之前啟動,因此getaddrinfo()失敗。這應該沒問題;pianod設置為每 60 秒重試一次網路登錄。

(旁白:在開始之前,我嘗試了明顯的方法systemd來等待網路堆棧pianod,但它不起作用。在systemd列表中,我被告知如果網路不可用,我真的應該嘗試讓我的程序表現良好,我可以欣賞的觀點。還有其他黑客可以讓我的程序在啟動期間休眠等。如果有這樣的黑客出於某種原因實際上是標準的,我會很感興趣,但更喜歡乾淨的解決方案。)

儘管pianod在初始啟動失敗後每 60 秒重試一次網路,但getaddrinfo()仍然會返回EAI_NONAME. 如果我手動重新啟動該過程,一切正常。

問題似乎是在第一次呼叫getaddrinfo()on boot 時,res_init()被呼叫並嘗試載入/etc/resolv.conf. 由於 DHCP 尚未使用正確的 DNS 資訊初始化該文件(?),這會將錯誤的 DNS(我認為是本地主機)資訊載入到程序的全域_res變數中。然後該過程卡在EAI_NONAME.

添加手動重新呼叫以在呼叫res_init()失敗後重新載入 DNS 資訊getaddrinfo()使事情正常工作,即getaddrinfo()在啟動後 60 秒的第一次登錄重試時成功。

但是……我很驚訝這是一個問題。我有另一項服務基本上做同樣的事情,似乎不需要手冊res_init()。另一個過程做得更多fork(),但我看不出它會從壞的_res全域中逃脫。一般來說,我很驚訝 Linux 設置有這個問題。

所以我覺得我應該問問我在這裡可能會錯過什麼。我的解釋聽起來正確嗎?如果是這樣,為什麼上游沒有更好地處理?如果沒有,我還應該研究什麼?有更好的標準方法來處理這個問題嗎?

更新:根據要求,這是目前服務單元的描述。 我已經嘗試添加After=network.target以及Requires. 從systemd人們所說的來看,這些從一個發行版到下一個發行版都不可靠……

[Unit]
Description=Pandora Client Daemon
After=syslog.target

[Service]
EnvironmentFile=/etc/pianod.env
ExecStart=/usr/sbin/pianod $INITSCRIPT $USERFILE $PORT $LOGGING -nroot
Restart=on-abort

[Install]
WantedBy=multi-user.target

Unix 介面和內部設計可以追溯到網路配置非常靜態的時代。沒有筆記型電腦,也沒有 DHCP 分配的動態 IP 地址。因此,該系統並非旨在在網路配置更改時向應用程序發送事件。應用程序在啟動時讀取/etc/resolv.conf一次 DNS 配置,僅此而已。

應對不斷變化的網路配置的現代方法是執行本地 DNS 代理。誠然,這花了很長時間,但越來越多的發行版開始將此作為預設配置(我認為 Ubuntu 從 12.04 開始這樣做)。僅將 127.0.0.1 列為名稱伺服器/etc/resolv.conf,並讓您的 DNS 代理應對配置更改。

Dnsmasq是輕量級 DNS 代理和伺服器的流行選擇。除非您有充分的理由選擇另一個,否則請選擇它。這是 Ubuntu 使用的。這也是我的帶有 MIPS 處理器和 16MB RAM 的家用路由器所執行的,所以你的 Pi 的執行能力很強。

像往常一樣,Arch Linux 沒有提供開箱即用的工作配置,但wiki有清晰而詳細的說明。

引用自:https://unix.stackexchange.com/questions/89699