如何将套接字绑定到 ipv6 地址?
how can i bind socket to ipv6 address?
我正在尝试将 ipv4 应用程序移植到 ipv6,但我无法将套接字绑定到 ipv6 地址。
问题在这里:
err=bind(listening, (sockaddr*)&hint, sizeof(hint));
err
应该是 0 但在这段代码中它是 returns -1。出了什么问题?
SOCKET listening = socket(AF_INET6, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
cerr << "Can't create a socket! Quitting" << endl;
return;
}
int err;
// Bind the ip address and port to a socket
sockaddr_in6 hint;
hint.sin6_family = AF_INET6;
hint.sin6_flowinfo = 0;
hint.sin6_port = htons(54000);
hint.sin6_addr = in6addr_any;
err=bind(listening, (sockaddr*)&hint, sizeof(hint)); //<======= here
这可能取决于您的平台,但在 Linux 上,自 2.4 以来,sockaddr_in6
结构还包含一个 sin6_scope_id
成员用于定义 IPv6 范围,并且由于变量 hint
在栈上,里面有随机数据。
IPv6 范围描述了它是哪种地址:单播、多播、link 本地和其他一些,我对它们只有粗略的了解。但如果里面有垃圾,那可能是个问题。
建议通过将 sin6_scope_id
硬设置为零来排除此问题,或者(更好)在将内容分配给它之前将整个 sockaddr_in6
结构清零;我长期以来一直使用我的 sockaddr_in
变量来完成此操作,以确保我没有得到我不想要的垃圾。
memset(&hint, 0, sizeof hint);
是的,errno
真的很重要。
与其手动填充 sockaddr_in6
,您可以(并且应该)使用 getaddrinfo()
,让它为您分配一个正确填充的 sockaddr_in6
,例如:
int err;
SOCKET listening = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (listening == INVALID_SOCKET)
{
err = WSAGetLastError(); // or errno on non-Windows platforms...
cerr << "Can't create a socket! Error " << err << ". Quitting" << endl;
return;
}
// Bind the ip address and port to a socket
addrinfo hint = {};
hint.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
hint.ai_family = AF_INET6;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP;
addrinfo *res;
err = getaddrinfo("::0", "54000", &hint, &res);
if (err != 0)
{
cerr << "Can't get address to bind the socket! Error " << err << ". Quitting" << endl;
closesocket(listening); // or close() on non-Windows platforms...
return;
}
err = bind(listening, res->ai_addr, res->ai_addrlen);
if (err == SOCKET_ERROR)
{
err = WSAGetLastError(); // or errno on non-Windows platforms...
cerr << "Can't bind the socket! Error " << err << ". Quitting" << endl;
freeaddrinfo(res);
closesocket(listening); // or close() on non-Windows platforms...
return;
}
freeaddrinfo(res);
...
我正在尝试将 ipv4 应用程序移植到 ipv6,但我无法将套接字绑定到 ipv6 地址。
问题在这里:
err=bind(listening, (sockaddr*)&hint, sizeof(hint));
err
应该是 0 但在这段代码中它是 returns -1。出了什么问题?
SOCKET listening = socket(AF_INET6, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
cerr << "Can't create a socket! Quitting" << endl;
return;
}
int err;
// Bind the ip address and port to a socket
sockaddr_in6 hint;
hint.sin6_family = AF_INET6;
hint.sin6_flowinfo = 0;
hint.sin6_port = htons(54000);
hint.sin6_addr = in6addr_any;
err=bind(listening, (sockaddr*)&hint, sizeof(hint)); //<======= here
这可能取决于您的平台,但在 Linux 上,自 2.4 以来,sockaddr_in6
结构还包含一个 sin6_scope_id
成员用于定义 IPv6 范围,并且由于变量 hint
在栈上,里面有随机数据。
IPv6 范围描述了它是哪种地址:单播、多播、link 本地和其他一些,我对它们只有粗略的了解。但如果里面有垃圾,那可能是个问题。
建议通过将 sin6_scope_id
硬设置为零来排除此问题,或者(更好)在将内容分配给它之前将整个 sockaddr_in6
结构清零;我长期以来一直使用我的 sockaddr_in
变量来完成此操作,以确保我没有得到我不想要的垃圾。
memset(&hint, 0, sizeof hint);
是的,errno
真的很重要。
与其手动填充 sockaddr_in6
,您可以(并且应该)使用 getaddrinfo()
,让它为您分配一个正确填充的 sockaddr_in6
,例如:
int err;
SOCKET listening = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (listening == INVALID_SOCKET)
{
err = WSAGetLastError(); // or errno on non-Windows platforms...
cerr << "Can't create a socket! Error " << err << ". Quitting" << endl;
return;
}
// Bind the ip address and port to a socket
addrinfo hint = {};
hint.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
hint.ai_family = AF_INET6;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP;
addrinfo *res;
err = getaddrinfo("::0", "54000", &hint, &res);
if (err != 0)
{
cerr << "Can't get address to bind the socket! Error " << err << ". Quitting" << endl;
closesocket(listening); // or close() on non-Windows platforms...
return;
}
err = bind(listening, res->ai_addr, res->ai_addrlen);
if (err == SOCKET_ERROR)
{
err = WSAGetLastError(); // or errno on non-Windows platforms...
cerr << "Can't bind the socket! Error " << err << ". Quitting" << endl;
freeaddrinfo(res);
closesocket(listening); // or close() on non-Windows platforms...
return;
}
freeaddrinfo(res);
...