【发布时间】:2014-02-27 06:11:14
【问题描述】:
背景
我们有一个小型无头机器,运行 Linux 内核 2.6.35 和 ARM 硬件上的 Open Embedded 发行版的一些变体。
据我们所知,我们使用的是 glibc 2.10.1。
盒子有一个未连接的以太网和一个串行连接的 GSM/3G 调制解调器。我们已配置 PPP 以确保继续连接到 Internet。这部分工作没有问题。
我们有一个用 c(实际上是 c++)编写的程序,它使用套接字建立一些连接。该程序使用 pthread 进行大量多线程处理。
要查找要连接的 IP 地址,我们使用 gethostbyname()。
当没有连接到互联网时,例如在初始启动期间或从调制解调器中移除 SIM 卡时,gethostbyname() 会返回 NULL。
症状
但有时 gethostbyname() 会一直返回 NULL,即使 Internet 连接已启动并正在运行。
使用时来自 getaddrinfo() 的错误代码是 EAI_NONAME ~“名称或服务未知”。我们手头没有来自 gethostbyname() 的错误代码,但它是等价的。
我们的分析
我们已通过(通过串行控制台)确保互联网连接正常
- 列表项
- 查看 /var/log/messages 并确保 pppd 一切正常
- ping 主机名(转换为 IP 并回复正常)
- 通过公共 IP 通过 ssh 连接到盒子
我们在进程中有两个线程对同一主机使用 gethostbyname()。它们的代码路径和函数略有不同,但对套接字函数使用通用代码,包括调用 gethostbyname() 的部分。
在 gethostbyname() 不断返回 NULL 的情况下,这通常只适用于其中一个线程,而不是每次都相同。另一个使查找完美。
此外,gethostbyname() 失败的线程可以很容易地通过简单的受控停止该线程并重新启动函数来运行,然后在 pthread-wise 中产生一个新线程。
总的来说,我们确信 DNS 翻译和互联网连接在操作系统级别运行良好。
为了排除线程问题,我们使用 getaddrinfo() 重新实现了查找代码,根据手册页它是可重入的。并得到完全相同的结果。
对我们来说,线程的退出似乎会导致某种清理,从而影响 gethostbyname()/getaddrinfo() 进行查找的能力。
一种解决方法是强制退出失败的线程,但这意味着应用程序结构的重大变化,并不是真正的选择。
问题
所以问题是:您是否有任何指示可以在哪里寻找解决方案或真正的问题可能在哪里?
【问题讨论】:
-
是在相同的主机名查找上失败,还是在“随机”名称上失败? DNS 默认使用 UDP,它可以静默丢包。但是如果响应对于单个 UDP 包来说太大,DNS 也可以使用 TCP,如果 DNS/TCP 有防火墙,您将没有响应并且查找失败
-
如果您使用 nslookup 从命令行执行 DNS 查询(例如 nslookup google.com),它会解析吗?如果是这样,这可能表明您的程序内部存在问题。如果不是,这可能表明您的平台上存在一些潜在的 DNS 问题。
-
我们只有一个特定的主机名,没有尝试过其他任何主机名,因为这是我们需要连接的特定主机。但如前所述,它不会始终失败。同一进程中的不同线程可以毫无问题地进行查找,并且重新启动线程可以恢复这种情况。
-
@mti2935 我们非常确定这是一个内部问题。从命令行查找有效。
-
你使用什么样的 libc (glibc/eglibc/uclibc/etc.) 和版本?还报告了什么样的错误(带有 errno 或 getaddrinfo 的返回值)
标签: c linux getaddrinfo gethostbyname