首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >getaddrinfo和INADDR_ANY

getaddrinfo和INADDR_ANY
EN

Stack Overflow用户
提问于 2017-10-08 01:17:25
回答 1查看 3.5K关注 0票数 3

花了几个小时搜寻,仍然很困惑。根据我所发现的,INADDR_ANY的意思是指定套接字将接受与分配给服务器的任何地址的连接。但是,以下情况导致客户端只能从同一台计算机连接到localhost:7777

代码语言:javascript
复制
addrinfo hints;
addrinfo* result;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(INADDR_ANY, "7777", &hints, &result);

SOCKET listenSocket = INVALID_SOCKET;
listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);

bind(listenSocket, result->ai_addr, (int)result->ai_addrlen);

我找到的唯一解决方案是将INADDR_ANY更改为机器的本地IP:

代码语言:javascript
复制
getaddrinfo("192.168.0.105", "7777", &hints, &result);

我需要理解INADDR_ANY是如何工作的,因为我觉得我只是在滥用它。任何帮助都将不胜感激。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-10-08 03:04:05

INADDR_ANY与你的问题无关。

getaddrinfo()的第一个参数是指定IP地址或主机名的const char *。但是INADDR_ANY却是一个整数。您的代码甚至编译的唯一原因是因为INADDR_ANY被定义为整数常数0,这是唯一允许分配给指针的整数常量。因此,实际上是将NULL传递给第一个参数。在这种情况下,这是很好的,因为这是你无论如何需要的。

您没有考虑到的是,getaddrinfo()返回一个链接的地址列表,其中可能包含多个地址,特别是如果您使用AF_UNSPEC。使用这个家族告诉getaddrinfo(),它可以返回IPv4和IPv6的地址。但是您只使用列表中的第一个地址,它恰好对应于localhost ( IPv4中的127.0.0.1,IPv6中的:1)。

对于服务器,您应该为输出列表中的每个地址创建并绑定一个单独的侦听套接字。这将使您可以绑定到与传递给getaddrinfo()的条件相匹配的所有地址,例如:

代码语言:javascript
复制
addrinfo hints = {};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;

addrinfo* result;

if (getaddrinfo(NULL, "7777", &hints, &result) == 0)
{
    for (addrinfo *addr = result; addr != NULL; addr = addr->ai_next)
    {
        SOCKET listenSocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
        if (listenSocket != INVALID_SOCKET)
        {
            bind(listenSocket, addr->ai_addr, (int)addr->ai_addrlen);
            listen(listenSocket, ...);
            // store listenSocket in a list for later use... 
        }
    }
    freeaddrinfo(result);
}

// use listening sockets as needed... 

或者,正如Sam在评论中提到的那样,您可以跳过getaddrinfo(),在这种情况下它并不能真正帮助您。您可以直接创建和绑定两个套接字,一个用于IPv4,一个用于IPv6:

代码语言:javascript
复制
SOCKET listenSocket4 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket4 != INVALID_SOCKET)
{
    sockaddr_in addr = {};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(7777);
    addr.sin_addr.s_addr = INADDR_ANY;

    bind(listenSocket4, (sockaddr*) &addr, sizeof(addr));
    listen(listenSocket4, ...);
}

SOCKET listenSocket6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket6 != INVALID_SOCKET)
{
    sockaddr_in6 addr = {};
    addr.sin6_family = AF_INET6;
    addr.sin6_port = htons(7777);
    addr.sin6_addr = in6addr_any;

    bind(listenSocket6, (sockaddr*) &addr, sizeof(addr));
    listen(listenSocket6, ...);
}

// use listening sockets as needed... 

或者更好的是,创建并绑定一个同时支持IPv4和IPv6的IPv4套接字:

代码语言:javascript
复制
SOCKET listenSocket = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket != INVALID_SOCKET)
{
    BOOL off = FALSE;
    setsockopt(listenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&off, sizeof(off));

    sockaddr_in6 addr = {};
    addr.sin6_family = AF_INET6;
    addr.sin6_port = htons(7777);
    addr.sin6_addr = in6addr_any;

    bind(listenSocket, (sockaddr*) &addr, sizeof(addr));
    listen(listenSocket, ...);
}

// use listening socket as needed... 
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46626660

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档