首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Bind() Windows使用IPv4,但不使用IPv6

Bind() Windows使用IPv4,但不使用IPv6
EN

Stack Overflow用户
提问于 2019-10-02 15:51:07
回答 1查看 669关注 0票数 1

我正在学习如何使用Winsock。我正在编写一个监听连接的服务器。一切都很好,直到我想将整个代码改为IPv6。

我已经浏览了所有与这个主题相关的问题和网站,但没有一个适合我的解决方案.:/

背景: Windows,使用VisualStudio2019,IPv6被激活并正常工作(例如,我可以在IPv6中使用我的手机)。

每次我得到错误10049。这个文件告诉我给定的IP是无效的。我试过了在ipconfig::1中能找到的每一个。

代码语言:javascript
复制
int slisten;
long res;
SOCKET client;

WSADATA wsaData;

res = WSAStartup(MAKEWORD(2, 1), &wsaData);
if (res == 0)
    cout << "WSAStartup()\t\t successful" << endl;
else
    cout << "error WSAStartup(): " << WSAGetLastError() << endl;

slisten = socket(PF_INET6, SOCK_STREAM, 0);
if (slisten != INVALID_SOCKET)
    cout << "socket()  \t\t successful" << endl;
else
    cout << "error socket(): " << WSAGetLastError() << endl;

//IPv6
struct sockaddr_in6 ip6addr;
ip6addr.sin6_family = AF_INET6;
ip6addr.sin6_port = htons(55339);
inet_pton(AF_INET6, "::1", &ip6addr.sin6_addr);

res = bind(slisten, (struct sockaddr*) & ip6addr, sizeof ip6addr);
if (res == SOCKET_ERROR)
{
    wprintf(L"bind function failed with error: %d\n", WSAGetLastError());
}

/* IPv4, not in use
struct sockaddr_in ip4addr;
ip4addr.sin_family = AF_INET;
ip4addr.sin_port = htons(3490);
inet_pton(AF_INET, "127.0.0.1", &ip4addr.sin_addr);

res = bind(slisten, (struct sockaddr*) & ip4addr, sizeof ip4addr);
if (res == SOCKET_ERROR)
{
    wprintf(L"bind function failed with error: %d\n", WSAGetLastError());
}
*/

IPv4方法可以工作,但是IPv6不工作。

WSAStartup() =成功

socket() =成功

bind() =错误10049

如果我注释掉IPv6部件,取消对IPv4部件的注释,并将PF_INET6更改为slisten = socket()中的PF_INET,则没有bind()错误。

告诉我您是否需要更多的代码或其他东西,但我的意思是,如果程序向该特定函数抛出错误,那么在此之前的一切都必须正常工作,因为没有错误(?)。

代码的某些部分属于s41b0tproductions on YouTube。你可以在https://www.youtube.com/user/s41b0tproductions/videos找到他。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-10-02 17:15:41

调用socket()时,PF_INET/PF_INET6应该改为AF_INET/AF_INET6。但是这通常并不重要,因为PF_...AF_...宏通常映射到相同的数值。

但是,更重要的是,在填充sockaddr_in/sockadr_in6结构之前,不要将它们归零。在使用Win32 API结构之前,应该始终将它们清零。对于AF_INET,不使用零填充sockaddr_in::sin_zero字段,因此它将包含调用堆栈中的随机字节。这通常是可以的,因为该字段通常被忽略。但是对于AF_INET6,您没有填充sockaddr_in6::sin6_flowinfosockaddr_in6::sin6_scope_id字段,它们确实有意义,并且可能是当它们包含随机值时导致WSAEADDRNOTAVAIL错误的根本原因。

用这个代替:

代码语言:javascript
复制
struct sockaddr_in6 ip6addr = {};
代码语言:javascript
复制
struct sockaddr_in ip4addr = {};

或者:

代码语言:javascript
复制
struct sockaddr_in6 ip6addr;
ZeroMemory(&ip6addr, sizeof ip6addr);
代码语言:javascript
复制
struct sockaddr_in ip4addr;
ZeroMemory(&ip4addr, sizeof ip4addr);

但是,为sockaddr_in(和connect())创建正确填充的bind() /sockaddr_in6结构的更好方法是使用getaddrinfo()而不是手动填充它们:

代码语言:javascript
复制
const char szHost = "::1"; // or "127.0.0.1"
const char *szPort = "55339";

addrinfo hint = {};
hint.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
hint.ai_family = AF_INET6; // or AF_INET
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP;

addrinfo *addr = NULL;
res = getaddrinfo(szHost, szPort, &hint, &addr);
if (res != 0)
{
    wprintf(L"getaddrinfo function failed with error: %d\n", res);
}
else
{
    res = bind(slisten, addr->ai_addr, addr->ai_addrlen);
    if (res == SOCKET_ERROR)
    {
        wprintf(L"bind function failed with error: %d\n", WSAGetLastError());
    }

    freeaddrinfo(addr);
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58205051

复制
相关文章

相似问题

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