【问题标题】:IPv6 client cannot connect to IPv6 server, cannot assign requested addressIPv6 客户端无法连接到 IPv6 服务器,无法分配请求的地址
【发布时间】:2021-10-28 18:56:49
【问题描述】:

重用代码 here 重现 tcp 客户端/服务器交互。

服务器初始化正常,开始监听连接。

但是,在运行客户端 ./client 时,客户端失败并显示消息

connect(): 无法分配请求的地址

链接above(也粘贴在下面)中的“失败”代码在哪里:

ret = connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (ret == -1) {
  perror("connect()");
  close(sock_fd);
  return EXIT_FAILURE;
}

当我运行ifconfig 时,我看不到 IPv6 地址。这是一个可能的解释吗?我在 OSX 机器上运行 Ubuntu Docker 映像。

代码很容易编译/运行

gcc server.c -o server
gcc client.c -o client
./server 
./client

服务器.c

    #include <arpa/inet.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <netinet/in.h>
     
    #define CLIENT_QUEUE_LEN 10
    #define SERVER_PORT 7002
     
    int main(void)
    {
        int listen_sock_fd = -1, client_sock_fd = -1;
        struct sockaddr_in6 server_addr, client_addr;
        socklen_t client_addr_len;
        char str_addr[INET6_ADDRSTRLEN];
        int ret, flag;
        char ch;
     
        /* Create socket for listening (client requests) */
        listen_sock_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
        if(listen_sock_fd == -1) {
            perror("socket()");
            return EXIT_FAILURE;
        }
     
        /* Set socket to reuse address */
        flag = 1;
        ret = setsockopt(listen_sock_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
        if(ret == -1) {
            perror("setsockopt()");
            return EXIT_FAILURE;
        }

        server_addr.sin6_family = AF_INET6;
        server_addr.sin6_addr = in6addr_any;
        server_addr.sin6_port = htons(SERVER_PORT);
     
        /* Bind address and socket together */
        ret = bind(listen_sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
        if(ret == -1) {
            perror("bind()");
            close(listen_sock_fd);
            return EXIT_FAILURE;
        }
     
        /* Create listening queue (client requests) */
        ret = listen(listen_sock_fd, CLIENT_QUEUE_LEN);
        if (ret == -1) {
            perror("listen()");
            close(listen_sock_fd);
            return EXIT_FAILURE;
        }
     
        client_addr_len = sizeof(client_addr);
     
        while(1) {
            /* Do TCP handshake with client */
            client_sock_fd = accept(listen_sock_fd,
                    (struct sockaddr*)&client_addr,
                    &client_addr_len);
            if (client_sock_fd == -1) {
                perror("accept()");
                close(listen_sock_fd);
                return EXIT_FAILURE;
            }
     
            inet_ntop(AF_INET6, &(client_addr.sin6_addr),
                    str_addr, sizeof(str_addr));
            printf("New connection from: %s:%d ...\n",
                    str_addr,
                    ntohs(client_addr.sin6_port));
     
            /* Wait for data from client */
            ret = read(client_sock_fd, &ch, 1);
            if (ret == -1) {
                perror("read()");
                close(client_sock_fd);
                continue;
            }
     
            /* Do very useful thing with received data :-) */
            ch++;
     
            /* Send response to client */
            ret = write(client_sock_fd, &ch, 1);
            if (ret == -1) {
                perror("write()");
                close(client_sock_fd);
                continue;
            }
     
            /* Do TCP teardown */
            ret = close(client_sock_fd);
            if (ret == -1) {
                perror("close()");
                client_sock_fd = -1;
            }
     
            printf("Connection closed\n");
        }
        return EXIT_SUCCESS;
    }

client.c

    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/socket.h>
    #include <unistd.h>
     
    #define SERVER_PORT 7002
     
    int main(int argc, char *argv[])
    {
        int sock_fd = -1;
        struct sockaddr_in6 server_addr;
        int ret;
        char ch = 'a';
     
        /* Arguments could be used in getaddrinfo() to get e.g. IP of server */
        (void)argc;
        (void)argv;
     
        /* Create socket for communication with server */
        sock_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
        if (sock_fd == -1) {
            perror("socket()");
            return EXIT_FAILURE;
        }
     
        /* Connect to server running on localhost */
        server_addr.sin6_family = AF_INET6;
        inet_pton(AF_INET6, "::1", &server_addr.sin6_addr);
        server_addr.sin6_port = htons(SERVER_PORT);
     
        /* Try to do TCP handshake with server */
        ret = connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
        if (ret == -1) {
            perror("connect()");
            close(sock_fd);
            return EXIT_FAILURE;
        }
     
        /* Send data to server */
        ret = write(sock_fd, &ch, 1);
        if (ret == -1) {
            perror("write");
            close(sock_fd);
            return EXIT_FAILURE;
        }
     
        /* Wait for data from server */
        ret = read(sock_fd, &ch, 1);
        if (ret == -1) {
            perror("read()");
            close(sock_fd);
            return EXIT_FAILURE;
        }
     
        printf("Received %c from server\n", ch);
     
        /* DO TCP teardown */
        ret = close(sock_fd);
        if (ret == -1) {
            perror("close()");
            return EXIT_FAILURE;
        }
     
        return EXIT_SUCCESS;
    }

【问题讨论】:

    标签: c docker ubuntu tcp ipv6


    【解决方案1】:

    因此,当我在具有基于运行 ifconfig 的 IPv6 地址的非 docker 容器(主机)上运行代码时,我得到了输出

    从服务器收到 b

    这似乎证实了我对容器不支持 IPv6 的怀疑。

    如果有人想详细说明,欢迎他们。

    【讨论】:

      【解决方案2】:

      您的 server_addr.sin6_flowspec 和该结构的其他成员未初始化。

      首先将您的 server_addr 实例清零,然后再将其传递给 connect

      在声明时要么这样做:

      struct sockaddr_in6 server_addr = {0};
      

      或者在开始分配该结构值的成员之前,调用 memset 将其全部填充为零。

      memset(&server_addr, '\0', sizeof(server_addr));
      

      我相信这会解决您的问题。如果没有,请继续阅读。

      如果上述方法不能解决您的问题,可能是因为您没有正确初始化 sin6_flowspec 或 sockaddr_in6 结构中不在 ipv4 sockaddr_in 结构中的其他成员。您可以利用 getaddrinfo 为您完成繁重的工作以正确填写这些字段。

      int result = 0;
      addrinfo* resultList = NULL;
      addrinfo hints = {};
      
      hints.ai_family = AF_INET6;
      hints.ai_flags |= AI_NUMERICHOST; // comment this line out if getaddrinfo fails
      hints.ai_socktype = SOCK_STREAM;
      
      int result = getaddrinfo("::1", NULL, &hints, &resultList);
      
      if ((result == 0) && (resultList->ai_family == AF_INET6))
      {
          memcpy(&server_addr, resultList->ai_addr, sizeof(sockaddr_in6));
          server_addr.sin6_port = htons(SERVER_PORT);
      }
      else
      {
         // fail
      }
      
      if (resultList)
      {
          freeaddrinfo(&resultList);
      }
      resultList = NULL;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-24
        • 2012-10-28
        • 2018-07-16
        • 2017-04-13
        • 2020-04-26
        相关资源
        最近更新 更多