WinSock连接前绑定导致WSAEADDRNOTAVAIL-请求的地址在其上下文中无效

WinSock bind before connects results in WSAEADDRNOTAVAIL - The requested address is not valid in its context

本文关键字:地址 上下文 无效 请求 连接 绑定 WSAEADDRNOTAVAIL- WinSock      更新时间:2023-10-16

我需要使用WinSock从特定的本地网卡打开一个套接字。我问过这个问题,在这里得到了答案。简而言之,答案建议您首先绑定到本地接口,然后调用connect。

然而,当我这样做时,我会得到一个WSAEADDRNOTAVAIL(10049)"请求的地址在其上下文中无效。"。为什么会这样?

假设下面的示例代码是在本地框192.168.1.3上运行的应用程序的一部分,并且正试图连接到远程服务器192.168.1.4。我已经反复检查了本地和远程地址是否正确。我可以双向ping(从本地到远程和从远程到本地)。

我已经为本地尝试了0以外的端口;没有区别。如果我在连接之前删除绑定,它就会工作,但我无法指定网络接口。

那么,你知道我为什么一直服用WSAEADDRNOTAVAIL吗?

addrinfo localhints = {0};
localhints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
localhints.ai_family = AF_INET;
localhints.ai_socktype = SOCK_STREAM;
localhints.ai_protocol = IPPROTO_TCP;
addrinfo *localaddr = NULL;
getaddrinfo("192.168.1.3", "0", &localhints, &localaddr);
bind(s, localaddr->ai_addr, localaddr->ai_addrlen);
freeaddrinfo(localaddr);
addrinfo remotehints = {0};
remotehints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
remotehints.ai_family = AF_INET;
remotehints.ai_socktype = SOCK_STREAM;
remotehints.ai_protocol = IPPROTO_TCP;
addrinfo *remoteaddr = NULL;
getaddrinfo("192.168.1.4", "12345", &remotehints, &remoteaddr);
connect(s, remoteaddr->ai_addr, remoteaddr->ai_addrlen);
freeaddrinfo(remoteaddr);

EDIT:此示例代码有意不进行错误检查,以便以最有效的方式传达我的意图。

编辑2:绑定到192.168.1.3会导致连接失败。绑定127.0.0.1有效。是的,我100%确信192.168.1.3是正确的本地IP。

编辑3:对!一时兴起,我在家用电脑上试用了这个测试应用程序,效果很好。所以,至少代码确实有效,而且问题一定与我的工作电脑有关。

好吧,事实证明@captrap是对的。

我已经禁用了我的防火墙,但我不知道,我们的IT部门有一些其他的防火墙功能紧密集成到企业病毒扫描仪中(我无法卸载或禁用)。一旦我设法让IT暂时禁用它,一切都如预期的那样工作。

调用API函数时,始终检查错误代码,例如:

addrinfo localhints = {0};
localhints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
localhints.ai_family = AF_INET;
localhints.ai_socktype = SOCK_STREAM;
localhints.ai_protocol = IPPROTO_TCP;
addrinfo *localaddr = NULL;
int ret = getaddrinfo("192.168.1.3", "0", &localhints, &localaddr);
if (ret == 0)
{
    ret = bind(s, localaddr->ai_addr, localaddr->ai_addrlen);
    freeaddrinfo(localaddr);
    if (ret == 0)
    {
        addrinfo remotehints = {0};
        remotehints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
        remotehints.ai_family = AF_INET;
        remotehints.ai_socktype = SOCK_STREAM;
        remotehints.ai_protocol = IPPROTO_TCP;
        addrinfo *remoteaddr = NULL;
        ret = getaddrinfo("192.168.1.4", "12345", &remotehints, &remoteaddr);
        if (ret == 0)
        {
            ret = connect(s, remoteaddr->ai_addr, remoteaddr->ai_addrlen);
            freeaddrinfo(remoteaddr);
            if (ret == 0)
            {
                // connect succeeded...
                // can use getsockname() here to discover which port was actually bound to, if needed.
                // On some OS versions, bind() does not perform the actual binding immediately,
                // connect() does the actual binding instead since it can make more informed choices based on the target address being connected to...
            }
            else
            {
                // connect failed...
            }
        }
        else
        {
            // getaddrinfo() failed
        }
    }
    else
    {
        // bind failed
    }
}
else
{
    // getaddrinfo() failed...
}

代码实际有多远?