【问题标题】:getaddrinfo returns 2 results with localhostgetaddrinfo 使用 localhost 返回 2 个结果
【发布时间】:2013-01-21 14:37:43
【问题描述】:

我正在尝试将函数 getaddrinfo 与被动套接字/侦听器一起使用,而不是直接填充旧的 sockaddr 结构。 我的目的是打开一个套接字并将其绑定到一个端口。本质上,我正在构建一个服务器。

我不知道为什么,但getaddrinfo 返回 2 个结果;因此,在第二次下面的循环中,我调用 bind 它退出时出现错误消息“地址已在使用中”。 你知道如何解决这个问题以及将它放在一个循环中是否正确?

         struct addrinfo addr;
         memset(&addr,0,sizeof(addrinfo));
         addr.ai_family   = AF_INET;
         addr.ai_socktype = SOCK_STREAM;
         addr.ai_protocol = 0;
         addr.ai_flags    = AI_PASSIVE;

         struct addrinfo * rp,* result;
         getaddrinfo( "localhost","59001",&addr,&result );
         for( rp = result; rp != NULL; rp = rp->ai_next ){

              int sd = socket( AF_INET, SOCK_STREAM, 0 );
              if(-1==sd ){ 
              printf( "error creating the socket %m");
              return -1; 
              }             

             if( -1==bind( sd, result->ai_addr, result->ai_addrlen ) ){                 
             printf( "error binding %m")
             return -1;
             }

             if( -1== listen(sd, MAX_BACKLOG ) ){
             std::cerr << "listen didn't work" << std::endl;
             return -1;
             }       
         }

【问题讨论】:

  • 好吧,手册页说:“返回一个或多个 addrinfo 结构”。您应该在两个结果中选择正确的一个。
  • 谢谢,不。这将解决并完成我的工作!

标签: c linux sockets networking getaddrinfo


【解决方案1】:

这里发生了几件事。对于来自getaddrinfo() 的多个结果,那是因为它返回了一个 IPv4 地址和一个 IPv6 地址(两者都有)。至于“地址已被使用”,则需要设置SO_REUSEADDR选项。把这个放在你对socket()bind()的调用之间:

int opval = 1;
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

【讨论】:

  • 你好 Linuxios。你是对的,它有效。问题是(我现在才意识到)。我必须打电话也听(并最终接受)。一旦我打电话听,地址就会被使用,我得到了那个错误。在这种情况下,我必须丢弃 2 个结果中的哪一个(如果必须?)。
  • @AbruzzoForteeGentile:您应该使用第一个成功创建套接字的。
  • 好的。我会这样做,尽管它是 IPV4 或 IPV6(我会回去了解可能有什么区别)。非常感谢!
  • @AbruzzoForteeGentile:当然!很高兴为您提供帮助。
  • getaddrinfo() 在这种情况下不应返回 IPv4 和 IPv6 地址,因为 hints 地址系列被设置为 AF_INET,即仅 IPv4。如果 hints 地址系列被设置为 AF_UNSPEC,那么它可以返回 IPv4 和 IPv6 地址。因此,getaddrinfo() 返回多个地址这一事实意味着"localhost" 确实解析为多个 IPv4 地址,可能是127.0.0.1 以及像192.168.0.1 这样的实际网络适配器IP。
【解决方案2】:

这是在红帽机器上吗?有一个众所周知的错误,因为/etc/hosts/ 两次列出localhost,当您特别请求AF_INET 时,您实际上两次得到相同的结果;一次用于 IPv4,一次用于 IPv6。

另见https://bugzilla.redhat.com/show_bug.cgi?id=496300

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-27
    • 2018-01-06
    相关资源
    最近更新 更多