【问题标题】:getnameinfo() function on a dualstack socket returning incorrect IP address?双栈套接字上的 getnameinfo() 函数返回不正确的 IP 地址?
【发布时间】:2015-02-18 12:53:38
【问题描述】:

我在双栈套接字上使用 TCP accept() 函数。接下来,我尝试使用 getnameinfo() 打印 IPV4 映射的 Ipv6 客户端地址。对于 accept() 的第一个连接,getnameinfo() 正确返回 IPv4-Ipv6 客户端源地址。但是对于病房的第二个客户端,它返回与第一个相同的 IPv4 映射的 IPv6 地址。任何人都可以帮助我吗?

伪代码:

struct sockaddr_storage client_ip;
socklen_t sock_len = sizeof(client_ip);
char buffer[INET6_ADDRSTRLEN];
struct sockaddr_in sa4;
static char *pclient_ipv4_addr = NULL;

while(1)
{
  fd = accept(master_fd, (struct sockaddr*)&client_ip, &sock_len);

  if (!getnameinfo((struct sockaddr*)&client_ip, sock_len, buffer,
          sizeof(buffer),0,0,NI_NUMERICHOST))
  {
    pclient_ipv4_addr = buffer;
    if (client_ip.ss_family==AF_INET6)
    {
      struct sockaddr_in6 *sa6=(struct sockaddr_in6*)&client_ip;
      if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr))
      {
        memset(&sa4,0,sizeof(sa4));
        sa4.sin_family=AF_INET;
        sa4.sin_port=sa6->sin6_port;
        memcpy(&sa4.sin_addr.s_addr, sa6->sin6_addr.s6_addr+12, 4);
        memcpy(&client_ip, &sa4,sizeof(sa4));
        sock_len=sizeof(sa4);
        pclient_ipv4_addr = inet_ntoa(sa4.sin_addr);
        printf("IPV4 add is %s\n", pclient_ipv4_addr );
      }
    }

  }

  memset(buffer, 0 , INET6_ADDRSTRLEN);
}

例如:对于第一个客户端 pclient_ipv4_addr 是“192.168.208.13”,然后对于下一个客户端也是
pclient_ipv4_addr 正在打印相同的地址。 getnameinfo(0 的不可重入有什么问题吗?如何 可以解决这个吗?

【问题讨论】:

    标签: c linux sockets system-calls ipv4


    【解决方案1】:

    试试这样的:

    struct sockaddr_storage client_ip;
    socklen_t sock_len;
    
    while(1)
    {
      sock_len = sizeof(client_ip);
      fd = accept(master_fd, (struct sockaddr*)&client_ip, &sock_len);
    
      if (fd == -1)
        break;
    
      if (client_ip.ss_family==AF_INET)
      {
        struct sockaddr_in *sa4 = (struct sockaddr_in*) &client_ip;
        printf("IPv4 add is %s\n", inet_ntoa(sa4->sin_addr) );
      }
      else if (client_ip.ss_family==AF_INET6)
      {
        struct sockaddr_in6 *sa6 = (struct sockaddr_in6*) &client_ip;
        if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr))
        {
          struct in_addr a4;
          memcpy(&a4, sa6->sin6_addr.s6_addr+12, 4);
          printf("IPv4 add is %s\n", inet_ntoa(a4) );
        }
        else
        {
          char buffer[INET6_ADDRSTRLEN];
          if (getnameinfo((struct sockaddr*)&client_ip, sock_len, buffer, sizeof(buffer), 0, 0, NI_NUMERICHOST) == 0)
            printf("IPv6 add is %s\n", buffer );
        }
      }
    }
    

    【讨论】:

    • 谢谢。这解决了问题。此外,我已经从我的代码中删除了以下两行并且没有看到任何问题。 memcpy(&client_ip, &sa4,sizeof(sa4)); sock_len=sizeof(sa4);看起来 client_ip 和 sock_len 在病房第二次错误地传递给了 accept()。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-20
    • 1970-01-01
    • 2013-12-26
    • 2021-10-01
    • 2010-12-14
    • 1970-01-01
    相关资源
    最近更新 更多