C语言 将套接字绑定到 IPv6 地址
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13504934/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Binding Sockets to IPv6 Addresses
提问by tpar44
I am trying to write a web server that listens on both IPv4 and IPv6 addresses. However, the code that I originally wrote did not work. Then I found out that the IPv6 structures work for both IPv4 and IPv6. So now I use the IPv6 structures however, only the IPv4 addresses work. This post, why can't i bind ipv6 socket to a linklocal address, which said to add server.sin6_scope_id = 5;so I did that but it still does not accept IPv6 telnet connections. Any help would be greatly appreciated because I am thoroughly stumped.
Thanks!
我正在尝试编写一个同时侦听 IPv4 和 IPv6 地址的 Web 服务器。但是,我最初编写的代码不起作用。然后我发现 IPv6 结构适用于 IPv4 和 IPv6。所以现在我使用 IPv6 结构,但是只有 IPv4 地址有效。这篇文章,为什么我不能将 ipv6 套接字绑定到一个本地链接地址,它说要添加,server.sin6_scope_id = 5;所以我这样做了,但它仍然不接受 IPv6 telnet 连接。任何帮助将不胜感激,因为我彻底难倒了。
谢谢!
My code is below:
我的代码如下:
void initialize_server(int port, int connections, char* address)
{
struct sockaddr_in6 socket_struct;
/*Creates the socket*/
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
syslog(LOG_ERR, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}/*Ends the socket creation*/
/*Populates the socket address structure*/
socket_struct.sin6_family = AF_INET6;
if(address == NULL)
socket_struct.sin6_addr=in6addr_any;
else
{
inet_pton(AF_INET6, "fe80::216:3eff:fec3:3c22", (void *)&socket_struct.sin6_addr.s6_addr);
}
socket_struct.sin6_port =htons(port);
socket_struct.sin6_scope_id = 0;
if (bind(sock_fd, (struct sockaddr*) &socket_struct, sizeof(socket_struct)) < 0)
{
syslog(LOG_ERR, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}//Ends the binding.
if (listen(sock_fd, connections) <0)
{
syslog(LOG_ERR, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}//Ends the listening function
}//ends the initialize server function.
回答by TheHeadlessSourceMan
Saying "server.sin6_scope_id = 5;" is arbitrary. I fought with this awhile myself and discovered you need to use the actual scope of the actual interface you want to bind on. It can be found with an obsure but useful little function.
说“server.sin6_scope_id = 5;” 是任意的。我自己对此进行了一段时间的斗争,发现您需要使用要绑定的实际接口的实际范围。它可以找到一个晦涩但有用的小功能。
#include <net/if.h>
server.sin6_scope_id=if_nametoindex("eth0");
Of course, hardcoding it to one particular adapter is bad, shortsighted coding. A more complete solution is to loop through all of them and match on the ip address you're binding. The following is not perfect in that it doesn't account for quirks like having non-canonical addresses and two adapters with the same ip, etc. But besoverall, this sample function works great and should get you started.
当然,将它硬编码到一个特定的适配器是糟糕的、短视的编码。更完整的解决方案是遍历所有这些并匹配您绑定的 IP 地址。下面的内容并不完美,因为它没有考虑像具有非规范地址和两个具有相同 IP 的适配器等怪癖。但总的来说,这个示例函数运行良好,应该可以帮助您入门。
#include <string.h> // strcmp
#include <net/if.h> // if_nametoindex()
#include <ifaddrs.h> // getifaddrs()
#include <netdb.h> // NI_ constants
// returns 0 on error
unsigned getScopeForIp(const char *ip){
struct ifaddrs *addrs;
char ipAddress[NI_MAXHOST];
unsigned scope=0;
// walk over the list of all interface addresses
getifaddrs(&addrs);
for(ifaddrs *addr=addrs;addr;addr=addr->ifa_next){
if (addr->ifa_addr && addr->ifa_addr->sa_family==AF_INET6){ // only interested in ipv6 ones
getnameinfo(addr->ifa_addr,sizeof(struct sockaddr_in6),ipAddress,sizeof(ipAddress),NULL,0,NI_NUMERICHOST);
// result actually contains the interface name, so strip it
for(int i=0;ipAddress[i];i++){
if(ipAddress[i]=='%'){
ipAddress[i]='##代码##';
break;
}
}
// if the ip matches, convert the interface name to a scope index
if(strcmp(ipAddress,ip)==0){
scope=if_nametoindex(addr->ifa_name);
break;
}
}
}
freeifaddrs(addrs);
return scope;
}
回答by qqx
You're creating a socket in the AF_INETfamily, but then trying to bind it to an address in the AF_INET6family. Switch to using AF_INET6in your call to socket().
您正在系列中创建一个套接字AF_INET,但随后尝试将其绑定到系列中的一个地址AF_INET6。切换到AF_INET6在您的呼叫中使用socket()。

