在启动时调用 getaddrinfo() 的进程会永久陷入错误的 /etc/resolv.conf?

在启动时调用 getaddrinfo() 的进程会永久陷入错误的 /etc/resolv.conf?

pianod我正在使用 Arch Linux ARM 的 Raspberry Pi 上运行Pandora 客户端/服务器。我已pianod设置为在启动时作为服务运行。它在网络堆栈之前启动,因此getaddrinfo()失败。这应该没问题;pianod设置为每 60 秒重试一次网络登录。

(旁白:我尝试了一些明显的方法来systemd在开始之前等待网络堆栈pianod,但它不起作用。在systemd列表中,我被建议实际上我应该尝试让我的进程在网络不可用时表现良好,我可以欣赏的一个观点。还有其他一些技巧可以让我的进程在启动过程中休眠,等等。如果有这样的技巧由于某种原因实际上是标准的,我会很感兴趣,但更喜欢一个干净的解决方案。)

尽管pianod在启动时初始失败后每 60 秒重试一次网络,但getaddrinfo()仍然返回EAI_NONAME.如果我手动重新启动该过程,一切都会正常。

问题似乎是在第一次调用getaddrinfo()启动时,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

答案1

Unix 接口和内部设计可以追溯到网络配置非常静态的时代。没有笔记本电脑,也没有 DHCP 分配的动态 IP 地址。因此,系统并未设计为在网络配置更改时向应用程序发送事件。应用程序/etc/resolv.conf在启动时读取一次 DNS 配置,仅此而已。

应对不断变化的网络配置的现代方法是运行本地 DNS 代理。诚然,这花了很长时间,但越来越多的发行版开始将其作为默认配置(我认为 Ubuntu 从 12.04 开始这样做)。仅将 127.0.0.1 列为 中的名称服务器/etc/resolv.conf,并让您的 DNS 代理应对配置更改。

域名解析是轻量级 DNS 代理和服务器的流行选择。除非您有充分的理由选择另一个,否则请选择它。 Ubuntu 就是这么用的。我的带有 MIPS 处理器和 16MB RAM 的家用路由器也可以运行它,因此您的 Pi 的运行能力非常强大。

与往常一样,Arch Linux 并没有附带开箱即用的工作配置,但维基百科有清晰详细的说明。

相关内容