【问题标题】:Which addrinfo struct should be used in connect()?在 connect() 中应该使用哪个 addrinfo 结构?
【发布时间】:2015-02-07 15:51:57
【问题描述】:

我正在编写一个程序,它可以连接到不同的网站并请求和下载网页。我这样做很大程度上是为了学习和正确理解网络编程。我想知道getaddrinfo返回的指向struct addrinfo类型的链接列表的指针是否以任何特定顺序排列,如果是这样,选择连接的IP地址是否以任何方式起作用。

例如,如果我运行getaddrinfo("google.com", "http", &hints, &res)res 有时会拥有多达七个互联网地址。如果我连接到第一个或最后一个,会有什么不同吗?请注意,我已经研究了此功能的手册页,据我了解,我的问题没有在那里得到解答。

【问题讨论】:

  • 我猜该顺序与您查找的域的 DNS 条目相同。完成结果后不要忘记调用 freeaddrinfo()。
  • 谢谢,我相信你也部分回答了我在进一步研究时要研究的另一个问题。 (如果你很好奇,getaddrinfo 是如何获取这些信息的?,我打算在学完 libc 后阅读一些源代码)。
  • getaddrinfo 进行 DNS 查询。您可以在 wikipedia 上阅读相关内容。如果您有 Linux 命令行,则可以运行命令 dig 或 nslookup - 它们可能使用 getaddrinfo 但可能直接执行,因为它们提供所有信息。这是一个可让您访问的网站 - network-tools.com/nslook
  • 根据这里的手册页:linux.die.net/man/3/getaddrinfo "通常情况下,应用程序应该按照返回的顺序尝试使用地址。在getaddrinfo()中使用的排序函数是定义的在 RFC 3484 中;可以通过编辑 /etc/gai.conf(自 glibc 2.5 起可用)来调整特定系统的顺序。” 这建议研究 RFC 3484 应该会给你一些信息. ietf.org/rfc/rfc3484.txt
  • 我看到了这个,但这句话并没有说明为什么我应该使用第一个或它有什么不同。我只是说使用第一个。以我的拙见,如果我正在编写的特定程序将受益于使用最后一个地址。另外,我目前正在阅读该文本,但并不太了解。我没有在这里寻求帮助(到目前为止),因为我确信我可以用足够的时间解决。

标签: c sockets getaddrinfo


【解决方案1】:

由于您在一个链接列表中组织了多个addrinfo 结构,您应该对其进行迭代并尝试connect 直到连接成功。那就是:

struct addrinfo *ptr = res;

while (res != NULL) {
     int rc = connect(socket_fd, (sockaddr *) ptr->ai_addr, ptr->addr_len);
     if (rc == 0) 
         break; // we managed to connect successfully
     // handle error

这可能是必需的,因为 DNS 查找可以返回多个条目,因此需要有一个链接列表才能让您访问它们。 如果connect 成功,你就完成了;如果失败,您应该继续尝试查找返回的每个可用 IP,因此将指针推进到下一个元素。此外,考虑到connect 可能由于多种原因而失败,因此您需要检查errno 是否有可能允许进一步尝试的错误。正如@R.. 指出的那样,您还必须传递connect 一个新的套接字,因为地址族可能会改变,释放前一个; getaddrinfo 将为您提供帮助,因为此信息在 addrinfo 节点 (ai_family) 中提供。

但是,这通常不必要:第一个结果通常会起作用。就我个人而言,如果可能的话,我从来没有遇到过循环遍历链表的需要,但如果你可能需要的话,知道它仍然是件好事。

getaddrinfo(3)

链表可能具有多个 addrinfo 结构的原因有多种,包括:网络主机是多宿主的,可通过多种协议访问(例如,AF_INET 和 AF_INET6);或者可以从多种套接字类型(例如,一个 SOCK_STREAM 地址和另一个 SOCK_DGRAM 地址)获得相同的服务。通常,应用程序应尝试按照返回的顺序使用地址。 getaddrinfo() 中使用的排序函数在 RFC 3484 中定义;可以通过编辑 /etc/gai.conf(自 glibc 2.5 起可用)来调整特定系统的顺序。

【讨论】:

  • 仅在循环中执行connect 是行不通的,除非您强制使用地址系列(IPv4 或 IPv6)或使用AI_V4MAPPED 以便您可以同时对待两者。否则,您需要 close 并重新打开 socket,并为您尝试的每个地址提供正确的地址系列。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-05
相关资源
最近更新 更多