简体   繁体   English

无法将套接字绑定到IPv4和IPv6中的端口

[英]Cannot Bind Socket to Port in Both IPv4 and IPv6

I am new to socket programming, and was working on some scratch code to get a better feel for it, when I hit a snag. 我是套接字编程的新手,当遇到障碍时,我正在研究一些临时代码来更好地理解它。 Any guidance on what I am doing wrong would be much appreciated! 任何关于我做错事情的指导将不胜感激!

I am trying to write a simple program that binds and listens on a user specified port and sends a "Hello" message to any connection. 我试图编写一个简单的程序,该程序绑定并侦听用户指定的端口,并向任何连接发送“ Hello”消息。 For kicks, I figured I would just listen on the same port for all IPv4 and IPv6 addresses. 对于踢,我想我只会在同一端口上侦听所有IPv4和IPv6地址。 Here is a code snippet: 这是一个代码片段:

memset(&hints, 0, sizeof hints);
hints.ai_family   = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags    = AI_PASSIVE;

if ( getaddrinfo(NULL, argv[1], &hints, &res) != 0 ) { 
    printf("getaddrinfo failed!\n");
    return 1;
}

for ( addrinfo* p = res; p != NULL; p = p->ai_next ) { 
    inet_ntop(p->ai_family, get_addr_ptr(p->ai_addr), ipstr, sizeof ipstr);
    printf("Found IP: %s\n",ipstr);

    printf("\tGetting socket...\t");
    sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
    if ( sockfd == -1 ) { 
        perror("\t\tError");
        continue;
    }
    printf("OK\n");

    printf("\tBind Socket to Port...\t");
    if ( bind(sockfd, p->ai_addr, p->ai_addrlen) == -1 ) { 
        perror("\t\tError");
        close(sockfd);
        continue;
    }
    printf("OK\n");

    printf("\tListen on socket...\t");
    if ( listen(sockfd, BACKLOG) == -1 ){
        perror("\t\tError");
        continue;
    }
    printf("OK\n");
}

freeaddrinfo(res);
while (1) {/* accept connections */}

When I run the code, I get this output: 运行代码时,得到以下输出:

$ ./simpleServer 8080
Found IP: 0.0.0.0
    Getting socket...       OK
    Bind Socket to Port...  OK
    Listen on socket...     OK
Found IP: ::
    Getting socket...       OK
    Bind Socket to Port...
        Error: Address already in use

However, if I look at netstat when the program is running, I don't see any conflicting port tied to :: , or any other IPv6 address for that matter. 但是,如果我在程序运行时查看netstat ,则看不到与::绑定的任何冲突端口,或与此相关的任何其他IPv6地址。

I played a little bit more with this, and found that I can bind to the port with just IPv4 or just IPv6, but not both, which I don't understand. 我对此进行了更多研究,发现我可以仅使用IPv4或仅使用IPv6绑定到端口,但不能同时使用这两种端口,我不理解。 I have created two socket, with the following ai_addr's: 我创建了两个套接字,其中包含以下ai_addr:

  • Family: AF_INET Address Info: 0.0.0.0:8008 家族: AF_INET地址信息: 0.0.0.0:8008 : 0.0.0.0:8008
  • Family: AF_INET6 Address Info: :::8080 家庭: AF_INET6地址信息:::8080

I feel like I am probably missing something fundamental, but I cant see it. 我觉得我可能缺少一些基本知识,但我看不到。

Thanks! 谢谢!

The problem you're facing is probably that you're using Dual-Stack mode. 您面临的问题可能是您正在使用双栈模式。 At least on Linux (Others have it often disabled eg FreeBSD) specifying :: as address yields in binding to * as netstat or ss would put it. 至少在Linux上(其他人经常禁用它,例如FreeBSD),将::指定为地址,并绑定到netstatss表示的* This means, it accepts both IPv6 and IPv4 Addresses. 这意味着它接受IPv6和IPv4地址。 Though the IPv4 ones get mapped to ::ffff:<your normal ipv4 address> . 尽管IPv4 ::ffff:<your normal ipv4 address>映射到::ffff:<your normal ipv4 address> So I'm guessing the same problem occurred to you. 所以我想您也遇到了同样的问题。

You could use IPV6_V6ONLY socket option if af_family == AF_INET6 to not allow this behaviour. 如果af_family == AF_INET6 ,则可以使用IPV6_V6ONLY套接字选项来不允许这种行为。

IPV6_V6ONLY (since Linux 2.4.21 and 2.6) If this flag is set to true (nonzero), then the socket is restricted to sending and receiving IPv6 packets only. IPV6_V6ONLY(从Linux 2.4.21和2.6开始)如果此标志设置为true(非零),则套接字将被限制为仅发送和接收IPv6数据包。 In this case, an IPv4 and an IPv6 application can bind to a single port at the same time. 在这种情况下,IPv4和IPv6应用程序可以同时绑定到单个端口。 If this flag is set to false (zero), then the socket can be used to send and receive packets to and from an IPv6 address or an IPv4-mapped IPv6 address. 如果此标志设置为false(零),则套接字可用于与IPv6地址或映射了IPv4的IPv6地址之间收发数据包。

The argument is a pointer to a boolean value in an integer. 参数是一个指向整数的布尔值的指针。

The default value for this flag is defined by the contents of the file /proc/sys/net/ipv6/bindv6only. 此标志的默认值由文件/ proc / sys / net / ipv6 / bindv6only的内容定义。 The default value for that file is 0 (false). 该文件的默认值为0(假)。

Taken from man 7 ipv6 取自男子7 ipv6

Please note that you're overriding your previously created/binded/listened socket. 请注意,您正在覆盖以前创建/绑定/监听的套接字。 Also use gai_strerror to get a meaningful error from the return value of getaddrinfo . 还可以使用gai_strerrorgetaddrinfo的返回值中获取有意义的错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM