【问题标题】:IP address in TCP socketsTCP 套接字中的 IP 地址
【发布时间】:2011-10-01 06:05:44
【问题描述】:

我有一个根节点(服务器)通过 TCP 套接字连接到许多其他节点(客户端)。我想从服务器向客户端发送一些数据,但是每个节点的数据不同,并且取决于该节点的 IP 地址。

因此我应该有连接到服务器的每个节点的 IP 地址。我怎样才能获得这些信息?

【问题讨论】:

    标签: sockets tcp network-programming ip-address


    【解决方案1】:

    当您拨打accept(2)时,您可以选择检索客户的地址。

    int accept(int socket, struct sockaddr *restrict address,
        socklen_t *restrict address_len);
    

    您需要存储这些地址,然后将 send(2) 存储到您需要发送的每个地址。​​

    所以工作流程应该是这样的:

    • 保留已连接客户端的列表。当然,最初列表是空的
    • 当您接受连接时,将其详细信息推送到该列表(accept(2) 返回的地址和套接字)。
    • 当您需要向每个客户端发送内容时,只需遍历列表并发送(使用存储的套接字)

    一个棘手的部分是socklen_t *restrict address_len 是一个值结果参数,所以你需要小心。

    【讨论】:

      【解决方案2】:

      这是一个比第一次出现时更微妙的问题。

      如果客户端位于 NAT 后面,您可能会从多个客户端获得相同的 IP。这是完全自然和预期的行为。如果您需要区分同一 NAT 后面的多个客户端,则需要其他形式的唯一客户端 ID(例如,IP 地址端口)。

      【讨论】:

      • 他们没有坐在任何 NAT 后面
      【解决方案3】:

      只要您可以访问已连接 TCP 套接字的文件描述符列表,就可以轻松检索远程主机的地址。关键是getpeername() 系统调用,它允许您找出套接字远程端的地址。示例 C 代码:

      // This is ugly, but simpler than the alternative
      union {
          struct sockaddr sa;
          struct sockaddr_in sa4;
          struct sockaddr_storage sas;
      } address;
      socklen_t size = sizeof(address);
      
      // Assume the file descriptor is in the var 'fd':
      if (getpeername(fd, &address.sa, &size) < 0) {
          // Deal with error here...
      }
      
      if (address.sa.family == AF_INET) {
          // IP address now in address.sa4.sin_addr, port in address.sa4.sin_port
      } else {
          // Some other kind of socket...
      }
      

      【讨论】:

      • 如果你没有 FD,你根本不会和那些套接字通信……
      • 这基本上也是您从accept() 调用中获取值的方式(如cnicutar 的回答)。它的优点是不需要你记住它。
      • 最后一句话:从 IP 地址获取主机 name 非常昂贵(DNS 没有针对这种情况进行优化),也不一定能提供信息(许多主机没有有反向记录,或者地址可能因为NAT而被共享)。
      猜你喜欢
      • 1970-01-01
      • 2016-07-30
      • 2020-10-16
      • 2017-12-12
      • 2018-05-16
      • 1970-01-01
      • 1970-01-01
      • 2012-11-03
      • 2011-02-04
      相关资源
      最近更新 更多