分配随机可用端口的不是getaddrinfo()。当请求端口 0 时,bind() 会这样做。
getaddrinfo() 手册页是正确的。 node 和service 参数不能同时为NULL。您可以将 node 设置为 NULL 以获取 INADDR_ANY - 或 - 您可以将 service 设置为 NULL 以获取端口 0。但是,要同时获取两者,您必须:
-
将node 设置为NULL,将service 设置为"0",并将hints.ai_flags 设置为AI_PASSIVE | AI_NUMERICSERV。
-
将node 设置为"0.0.0.0" 并将service 设置为NULL(AI_PASSIVE 被忽略)
-
将node 设置为"0.0.0.0",将service 设置为"0",并将hints.ai_flags 设置为AI_NUMERICSERV(AI_PASSIVE 被忽略)
任何这些组合都会导致getaddrinfo() 返回指向sockaddr_in 的指针,该指针将其sin_addr 设置为INADDR_ANY,并将其sin_port 设置为0。
然后您可以使用sockaddr_inbind(),bind() 将选择一个随机可用端口,之后您可以使用getsockname() 检索该端口。
int server_fd = -1;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
struct addrinfo *result;
if( getaddrinfo(NULL, "0", &hints, &result) != 0 )
{
// error handling...
}
else if( (server_fd = socket(result->ai_family, result->ai_socktype, result->ai_protocol)) < 0 )
{
// error handling...
freeaddrinfo(result);
}
else if( bind(server_fd, result->ai_addr, result->ai_addrlen) < 0 )
{
// error handling...
close(server_fd);
freeaddrinfo(result);
}
else
{
freeaddrinfo(result);
// use server_fd as needed...
struct sockaddr_in bound_addr;
socklen_t addrlen = sizeof(bound_addr);
if( getsockname(server_fd, (struct sockaddr*)&bound_addr, &addrlen) < 0 )
{
// error handling...
}
else
{
// use ntohs(bound_addr.sin_port) as needed...
}
...
close(server_fd);
}
或者,由于您确切知道要 bind() 到什么,您可以简单地忽略 getaddrinfo() 并手动填充 sockaddr_in:
int server_fd;
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = 0;
if( (server_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0 )
{
// error handling...
}
else if( bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0 )
{
// error handling...
close(server_fd);
}
else
{
// use server_fd as needed...
struct sockaddr_in bound_addr;
socklen_t addrlen = sizeof(bound_addr);
if( getsockname(server_fd, (struct sockaddr*)&bound_addr, &addrlen) < 0 )
{
// error handling...
}
else
{
// use ntohs(bound_addr.sin_port) as needed...
}
...
close(server_fd);
}