c - 将套接字绑定(bind)到 IPv6 地址

标签 c sockets ipv6 ipv4 berkeley-sockets

我正在尝试编写一个同时监听 IPv4 和 IPv6 地址的网络服务器。但是,我最初编写的代码不起作用。然后我发现 IPv6 结构适用于 IPv4 和 IPv6。所以现在我使用 IPv6 结构,但是只有 IPv4 地址有效。此帖,why can't i bind ipv6 socket to a linklocal address ,它说要添加 server.sin6_scope_id = 5; 所以我这样做了,但它仍然不接受 IPv6 telnet 连接。任何帮助将不胜感激,因为我完全被难住了。
谢谢!

我的代码如下:

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.

最佳答案

说“server.sin6_scope_id = 5;”是任意的。我自己为此奋斗了一段时间,发现您需要使用要绑定(bind)的实际接口(interface)的实际范围。可以通过一个不起眼但有用的小功能找到它。

#include <net/if.h>
server.sin6_scope_id=if_nametoindex("eth0");

当然,将它硬编码到一个特定的适配器是糟糕的、短视的编码。一个更完整的解决方案是遍历所有这些并匹配您绑定(bind)的 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]='\0';
                    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;
}

关于c - 将套接字绑定(bind)到 IPv6 地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13504934/

相关文章:

python - 通过不同的 TCP 端口回显通过 UDP 接收的消息

c - C中的IPv6解析

c - 为什么内存会损坏?

c - 如何通过套接字 : one buffer, 分散/聚集或 readdir 发送数据?

python - 使用传输编码 Python 时出现 502 Bad gateway

linux - 从 ipv6 地址打开网站时出错

java - 如何从 Java 应用程序内部获取公共(public) IPV6 地址?

c - 回显服务器代码不工作

c - 为什么将整数左移 24 位会产生错误的结果?

python - 如何在Python中实现多线程? 【套接字编程】