从getaddrinfo()获取服务器ip 0.0.0.0:0

时间:2011-10-30 02:33:47

标签: c sockets

我正在关注关于NP的Beej指南。

我做了一些修改,并试图通过getaddrinfo()获取我的服务器程序的IP (原文可在此处找到http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#simpleserver

以下是我更改/添加的部分。

if ((rv = getaddrinfo(NULL, "0", &hints, &servinfo)) != 0) { //0 for random port?
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
    return 1;
 }

//... some code emitted ...

//freeaddrinfo(servinfo); //I still need it!


printf("ip: %s\nport: %d\n",
    inet_ntop(AF_INET, &((struct sockaddr_in *)p->ai_addr)->sin_addr, ip4, INET_ADDRSTRLEN),
    ntohs(((struct sockaddr_in *)p->ai_addr)->sin_port)
);

问题在于我得到了结果

ip: 0.0.0.0  
port: 0  

Q1:我从几个网站上读过,说端口设置为“0”告诉操作系统你想要下一个可用端口,而不是实际为0.这是真的吗?

Q2:我还读过gethostbyname(gethostname(...))可以给你机器的ip,但是Beej说这些被getaddrinfo()取代了。那么,我应该使用getaddrinfo吗?还是gethostbyname?

问题3:还有什么我做错了吗?

2 个答案:

答案 0 :(得分:8)

它正在回归你所期望的。

来自man getaddrinfo

  

如果在hints.ai_flags中指定了AI_PASSIVE标志,并且node为NULL,则返回的套接字地址将适合于绑定(2)将接受(2)连接的套接字。返回的套接字地址将包含“通配符地址”(IPv4地址为INADDR_ANY,IPv6地址为IN6ADDR_ANY_INIT)。通配符地址由打算接受任何主机网络地址上的连接的应用程序(通常是服务器)使用。如果node不为NULL,则忽略AI_PASSIVE标志。

您链接到的代码会将hints.ai_flags设置为AI_PASSIVE,并且您正在为节点传递NULL。通配符地址为0.0.0.0。按规定工作。绑定到该地址意味着您绑定到计算机上的每个IP地址。

至于港口......你指的是"0" ......这正是你要回来的。您需要将它设置为您希望侦听的实际端口,作为您链接的示例代码。

答案 1 :(得分:6)

  

Q1:我从几个网站上读过,说端口设置为“0”告诉操作系统你想要下一个可用端口,而不是实际为0.这是真的吗?

是的,但只有在您使用bind()将地址附加到真正的套接字之后。此时,使用getsockname()从套接字获取绑定地址;港口将是其中的一部分。

  

Q2:我还读过gethostbyname(gethostname(...))可以给你机器的ip,但是Beej说这些被getaddrinfo()取代了。那么,我应该使用getaddrinfo吗?还是gethostbyname?

使用getaddrinfo();它完成了gethostbyname()所做的所有事情以及更多,并且界面糟透了很多。 (例如,它通常是线程安全的。)

  

问题3:还有什么我做错了吗?

服务器的IP地址没有明确定义的概念。由于多个网卡(服务器比桌面系统更常见),服务器可能有很多,而外界认识的服务器可能不是其中之一(感谢NAT防火墙)。有时,您可以在客户端连接之前确切地知道消息的来源 - 最常见的选择是知道客户端将在localhost上 - 这是您在bind()期间设置的信息的一部分但那很少见。通过使用getpeername(),您可以找到客户端的地址,但NAT可能仍然在功能上无用。这些地址通常在部署期间在应用程序的配置文件中设置。

如果您只需要用于记录目的的信息,请继续。但要注意将它用于其他任何事情,因为它实际上并没有告诉你那么多。