1

我正在查看一些过时的代码,这些代码使用getaddrinfo并确定主机名信息,然后getnameinfo回退到如果失败。gethostnamegethostbynamegetnameinfo

现在,这对我来说似乎是错误的。我正在尝试了解代码的意图,以便提出建议。我不想在这里重新发布整个代码,因为它又长又复杂,但我会尝试总结一下:

据我所知,这段代码的重点是生成一个字符串,另一个进程可以使用该字符串连接到侦听套接字。这似乎不仅适用于本地进程,也适用于远程主机连接回这台计算机。

所以有问题的代码基本上是在做以下事情:

  • getaddrinfo(node = NULL, service = port, hints.ai_flags = AI_PASSIVE, ai);-- 这会得到一个可能的参数列表,socket()可以与bind().
  • 浏览结果列表并创建一个套接字。
  • 第一次成功创建套接字时,将其选为“已使用” addrinfo
  • 对于ai_addr选定的addrinfo,调用getnameinfo()以获取关联的主机名。
  • 如果失败,调用gethostname(),然后查看gethostbyname()结果。

我认为这是错误的有几个原因,但我想验证我的逻辑。首先,从一些实验看来,getnameinfo()这里几乎总是失败。我想输入地址是未知的,因为它是一个监听套接字,而不是一个目的地,所以从这个角度来看,它不需要一个有效的 IP。然后,调用gethostname()并将结果传递给gethostbyname()几乎总是返回与gethostname()自身相同的结果。换句话说,它只是验证本地主机名,对我来说似乎毫无意义。这是有问题的,因为远程主机甚至不一定可以使用它,是吗?

不知何故,我认为尝试在子网上确定您自己的主机名的整个想法可能不是那么有用,而是您必须向另一台主机发送一条消息并查看他们认为它是什么 IP 地址。(不幸的是,在这种情况下这没有意义,因为我不知道该程序级别的其他对等方。)例如,本地主机可能有多个 NIC,因此有多个 IP 地址,因此尝试确定单个主机地址对是无意义的。(正确的解决方法是bind()同时收听所有 addrinfo结果吗?)

我还注意到,只需将名称传递给getaddrinfo()并设置AI_CANONNAME标志即可解析名称,这意味着该getnameinfo()步骤可能是多余的。但是,我想这里没有这样做,因为他们试图在不提供先验信息的情况下确定主机名的某种公正视图。当然,它失败了,他们最终还是使用了gethostname()!我还尝试向 提供“localhost” getaddrinfo(),它会在 ai_canonname` 中报告 Linux 下的主机名,但在 OS X 上只会产生“localhost”,所以它不是那么有用,因为这应该是跨平台的。

我想总结一下,我的问题是,在现代套接字编程中,如果存在一个可以向子网对等方宣布的本地主机名,那么正确的方法是什么?我倾向于用简单地返回结果来替换这段代码gethostname(),但我想知道是否有更合适的解决方案使用现代调用,如getaddrinfo().

如果答案是没有办法做到这一点,我将不得不使用gethostname()反正,因为我必须在这里返回一些东西,否则会破坏 API。

4

2 回答 2

1

我认为你应该看看Ulrich Drepper关于 IPv6 编程的文章。它相对较短,可能会回答您的一些问题。我发现它真的很有用。我发布此链接,因为没有(至少)伪代码很难回答您的问题。

于 2012-09-05T03:28:40.870 回答
1

如果我没看错,您只想获得一个非本地主机套接字地址,该地址可能会成功创建本地套接字,并让远程主机重新连接。

我有一个我写的函数,你可以引用它,叫做“GetBestAddressForSocketBind”。你可以从我的 GitHub 项目页面上得到。您可能需要引用父目录中的一些代码。

该代码本质上只是使用getifaddrs来枚举适配器并选择第一个“启动”的适配器,而不是环回/本地并且具有所需地址系列(AF_INET 或 AF_INET6)的 IP 地址。

希望这可以帮助。

于 2012-09-05T04:08:32.733 回答