【发布时间】:2011-10-01 06:05:44
【问题描述】:
我有一个根节点(服务器)通过 TCP 套接字连接到许多其他节点(客户端)。我想从服务器向客户端发送一些数据,但是每个节点的数据不同,并且取决于该节点的 IP 地址。
因此我应该有连接到服务器的每个节点的 IP 地址。我怎样才能获得这些信息?
【问题讨论】:
标签: sockets tcp network-programming ip-address
我有一个根节点(服务器)通过 TCP 套接字连接到许多其他节点(客户端)。我想从服务器向客户端发送一些数据,但是每个节点的数据不同,并且取决于该节点的 IP 地址。
因此我应该有连接到服务器的每个节点的 IP 地址。我怎样才能获得这些信息?
【问题讨论】:
标签: sockets tcp network-programming ip-address
当您拨打accept(2)时,您可以选择检索客户的地址。
int accept(int socket, struct sockaddr *restrict address,
socklen_t *restrict address_len);
您需要存储这些地址,然后将 send(2) 存储到您需要发送的每个地址。
所以工作流程应该是这样的:
accept(2) 返回的地址和套接字)。一个棘手的部分是socklen_t *restrict address_len 是一个值结果参数,所以你需要小心。
【讨论】:
这是一个比第一次出现时更微妙的问题。
如果客户端位于 NAT 后面,您可能会从多个客户端获得相同的 IP。这是完全自然和预期的行为。如果您需要区分同一 NAT 后面的多个客户端,则需要其他形式的唯一客户端 ID(例如,IP 地址和端口)。
【讨论】:
只要您可以访问已连接 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...
}
【讨论】:
accept() 调用中获取值的方式(如cnicutar 的回答)。它的优点是不需要你记住它。