由于@Celada指出,getpeername()
作品在struct sockaddr *
其大小,在你的情况下,struct sockaddr_in
的一个,而不是大到足以容纳约IPv6地址信息。
这个struct sockaddr
将被实现为struct sockaddr_in
或struct sockaddr_in6
,这取决于套接字是处理IPv4还是IPv6地址。
你是分配 a struct sockaddr_in
它是16字节(仅用于IPv4地址的空间)。一个IPv6需要一个struct sockaddr_in6
这是28个字节,并且存储它的IP地址之后的16个第一字节。因此将struct sockaddr_in
读为struct sockaddr_in6
下一部分解释了为什么您可能会读取0.0.0.0:0
。如果您对解决方案更感兴趣,请直接转到最后一节。
你为什么要用你当前的代码读取一些归零的IP地址?
下面是这些结构的定义:
struct sockaddr_in {
short sin_family; // e.g. AF_INET, AF_INET6 <-- 2 bytes
unsigned short sin_port; // e.g. htons(3490) <-- 2 bytes
struct in_addr sin_addr; // (only contains IPv4 address) <-- 4 bytes
char sin_zero[8]; // zero this if you want to <-- 8 bytes
};
struct sockaddr_in6 {
u_int16_t sin6_family; // address family, AF_INET6 <-- 2 bytes
u_int16_t sin6_port; // port number, Network Byte Order <-- 2 bytes
u_int32_t sin6_flowinfo; // IPv6 flow information <-- 4 bytes
struct in6_addr sin6_addr; // IPv6 address <-- 16 bytes
u_int32_t sin6_scope_id; // Scope ID <-- 4 bytes
};
来源:Beej's Guide to Network Programming's struct sockaddr and pals page
因此,当你尝试从struct sockaddr_in
而getpeername()
与struct sockaddr_in6
信息填充它读取的IP地址,你实际上是阅读struct sockaddr_in6
的sin6_flowinfo
部分。该流量信息通常为零,除非连接明确标记了流量ID。 这就是为什么你会读取归零IP地址。
如何提供一个通用的存储,以便getpeername()
作品在这两种情况下,无需提前英特尔对等的连接类型(确实)的可能性?
这就是struct sockaddr_storage
在哪里踢!
这是您应该用来初始化空间以提供getpeername()
的类型,并将其转换为struct sockaddr *
。它的设计目的是保存的任何信息连接类型。
你的代码应该是:
socklen_t socklen;
struct sockaddr_storage client_addr;
socklen = sizeof(client_addr);
retval = getpeername(connfd, (struct sockaddr *)&client_addr, &socklen);
if(retval == -1) perror("getpeername error!\n");
要使用结构,你应该再转换回要么struct sockaddr_in
或struct sockaddr_in6
,这取决于你struct sockaddr_storage
的ss_family
字段的值。
if (addr.ss_family == AF_INET) {
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
port = ntohs(s->sin_port);
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
} else if(addr.ss_family == AF_INET6) {
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
port = ntohs(s->sin6_port);
inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
}
源(修改):Beej's Guide to Network Programming's getpeername() page
呀,因为IP地址长度从IPv4到IPv6的不同,没有泛型函数这样做对你来说,返回一个IP地址...因为你仍然需要知道您是否收到32位或128位,从而再次检查地址系列!
如果'getpeername()'成功,它永远不会报告0.0.0.0。 'getpeername()'返回一个错误代码?你显示的代码没有检查。 –
传输端点没有连接 – user1944267
难道这是因为你的代码假设它必须是套接字家族有时是'AF_INET6'而不是'AF_INET'?将'struct sockaddr_in6'解释为'struct sockaddr'会导致无意义的结果,可能为0.0.0.0。 – Celada