如何从C语言的sock结构中获取IP地址?

49

我正在编写简单的服务器/客户端,并尝试获取客户端的IP地址并将其保存在服务器端,以决定哪个客户端应该进入临界区。我多次搜索了谷歌,但无法找到从sock结构体中获取IP地址的适当方法。

我相信这是在服务器接受客户端请求之后从sock结构体中获取IP的一种方法。更具体地说,在c语言中,当服务器执行

csock = accept(ssock, (struct sockaddr *)&client_addr, &clen) 
感谢。
3个回答

60

假设您正在使用IPv4,则请执行以下操作:

struct sockaddr_in* pV4Addr = (struct sockaddr_in*)&client_addr;
struct in_addr ipAddr = pV4Addr->sin_addr;

如果你想要将 IP 地址转换为字符串,可以执行以下操作:

char str[INET_ADDRSTRLEN];
inet_ntop( AF_INET, &ipAddr, str, INET_ADDRSTRLEN );

IPv6也相当简单...

struct sockaddr_in6* pV6Addr = (struct sockaddr_in6*)&client_addr;
struct in6_addr ipAddr       = pV6Addr->sin6_addr;

获取一个字符串几乎与获取 IPV4 地址相同

char str[INET6_ADDRSTRLEN];
inet_ntop( AF_INET6, &ipAddr, str, INET6_ADDRSTRLEN );

2
你忘了将 str 缓冲区传递给 inet_ntop()。而且 sin_addr 是一个结构体 - 必须使用 sin_addr.s_addr。值得注意的是,IPv4地址以网络字节顺序存储,并且要将其视为十六进制数,需要使用 ntohl(pV4Addr->sin_addr.s_addr) - Dummy00001
你说得对,但也错过了我没有使用小写的"in6_addr";至于ntohl,我通常不太在意,因为只要两者都是网络字节序,我仍然可以进行相等性检查,而且这会破坏inet_ntop(不是吗?)。 - Goz
2
这个问题被标记为C语言 - 在像struct sockaddr_in *这样的类型中,你不能省略struct。此外,IPV4方法应该使用struct in_addr而不是int来存储地址,类似于你展示的IPV6方法。 - caf

46

提取IP地址和端口号的更简单和正确的方法如下:

printf("IP address is: %s\n", inet_ntoa(client_addr.sin_addr));
printf("port is: %d\n", (int) ntohs(client_addr.sin_port));

SoapBox的被接受的答案可能不适用于所有架构。参见大端和小端


27

假设 client_addr 是一个 struct sockaddr_in(通常情况下是这样)。您可以从 client_addr.sin_addr.s_addr 中获取 IP 地址(作为一个 32 位无符号整数)。

您可以通过以下方式将其转换为字符串:

printf("%d.%d.%d.%d\n",
  int(client.sin_addr.s_addr&0xFF),
  int((client.sin_addr.s_addr&0xFF00)>>8),
  int((client.sin_addr.s_addr&0xFF0000)>>16),
  int((client.sin_addr.s_addr&0xFF000000)>>24));

29
你应该使用inet_ntoa()函数代替手动操作位数。 - Remy Lebeau
14
inet_ntoa 不是线程安全的,虽然它在大多数情况下使用时可能并不重要。一个安全的替代品是 inet_ntop - jweyrich
@RemyLebeau 很好和简单。我喜欢它。 - James

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接