啟動時呼叫 getaddrinfo() 的程序永久卡在錯誤的 /etc/resolv.conf 中?
我正在
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有清晰而詳細的說明。