我正在使用我找到的一些代码,并试图理解其中的for 循环逻辑。
看起来 for 循环没有被使用并且它总是会中断。所以我不明白从 getaddrinfo() 返回什么样的信息会导致它再次循环并检查某些内容?
问题:基本上这个 for 循环想要完成什么?在我看来,它只是检查列表不为空,因为从来没有发生循环。
tcp_ctx* tcp_new_ctx(INT family, CHAR *host, CHAR *port) {
struct addrinfo *list = NULL;
struct addrinfo *e = NULL;
struct addrinfo hints;
tcp_ctx *c = NULL;
WSADATA wsa;
INT on = 1;
WSAStartup(MAKEWORD(2, 0), &wsa);
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// try to resolve network address for host
//list contains linked list of addrinfo structs containing information on the host
if (getaddrinfo(host, port, &hints, &list) != 0) {
return NULL;
}
c = tcp_alloc(sizeof(tcp_ctx));
// Traverse linked list from getaddr info
for (e = list; e != NULL; e = e->ai_next) {
if (family == AF_INET) {
memcpy(&c->v4, e->ai_addr, e->ai_addrlen);
c->ai_addr = (SOCKADDR*)&c->v4;
} else if (family == AF_INET6) {
memcpy(&c->v6, e->ai_addr, e->ai_addrlen);
c->ai_addr = (SOCKADDR*)&c->v6;
} else {
return NULL;
}
c->ai_addrlen = e->ai_addrlen;
// create socket and event for signalling
c->s = socket(family, SOCK_STREAM, IPPROTO_TCP);
if (c->s != SOCKET_ERROR) {
// ensure we can reuse same port later
setsockopt(c->s, SOL_SOCKET, SO_REUSEADDR, (CHAR*)&on, sizeof(on));
}
break;
}
freeaddrinfo(list);
return c;
}
Run Code Online (Sandbox Code Playgroud)
列表中会有什么?
以下引用来自glibc的手册页getaddrinfo,但据我所知,它同样适用于 Windows 版本:
链表可能具有多个 addrinfo 结构的原因有多种,包括: 网络主机是多宿主的,可通过多种协议访问(例如,AF_INET 和 AF_INET6);或者可以从多种套接字类型(例如,一个 SOCK_STREAM 地址和另一个 SOCK_DGRAM 地址)获得相同的服务。
因此,基本上主机可以有多种联系方式,并且getaddrinfo列出了所有(已知)方式。请注意,同一手册页进一步指出:
通常,应用程序应尝试按照返回的顺序使用地址。getaddrinfo() 中使用的排序函数在 RFC 3484 中定义;
当然,这里我们也不知道这是否也适用于 Windows 实现,但如果它在 RFC 中指定,那么情况可能就是这样。
这个 for 循环想要完成什么?
按照目前的情况,您可以删除循环。不过,我认为可能有理由保留(=修复)它:考虑第一个返回的条目的 a 既不是family也不AF_INET是 的情况AF_INET6。然后,您的问题中的代码就会失败(return NULL;),但列表中可能有一个稍后的条目可能包含该系列。