如何从getaddrinfo返回结果中正确提取并打印IP地址
直接访问
sa_data打印IP失败的原因 struct sockaddr是通用套接字地址占位结构,其成员sa_data存储的是二进制格式的原始地址数据,包含端口、IP等字段,不是以\0结尾的可打印文本字符串,直接用printf的%s格式符解析必然会出现乱码、截断问题。你测试时仅输出字符"a",是因为sa_data起始位置对应地址结构中的端口字段,若端口值的第一个字节刚好是ASCII码0x61(对应字符'a'),且下一个字节为0x00,%s遇到终止空字节就会停止输出,自然得不到有效IP。- 不建议直接手动解析
sa_data的内存布局:不同地址族对应的实际地址结构(IPv4对应struct sockaddr_in、IPv6对应struct sockaddr_in6)内存排布完全不同,硬编码偏移解析极易出错,可移植性极差。
专用转换函数与正确实现
系统提供了专用函数inet_ntop(),专门负责将二进制格式的网络地址转换为人类可读的文本格式IP字符串,同时支持IPv4和IPv6,是这个场景的标准实现方案。
使用时需要先引入头文件<arpa/inet.h>,修改你原来的连接成功分支代码即可:
if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) { char ip_buf[INET6_ADDRSTRLEN]; // 系统定义的宏,长度足够存储IPv4/IPv6文本地址 void *ip_addr; // 根据地址族将通用sockaddr结构转换为对应实际类型,取出IP字段指针 if (rp->ai_family == AF_INET) { struct sockaddr_in *v4_addr = (struct sockaddr_in *)rp->ai_addr; ip_addr = &v4_addr->sin_addr; } else { // AF_INET6 struct sockaddr_in6 *v6_addr = (struct sockaddr_in6 *)rp->ai_addr; ip_addr = &v6_addr->sin6_addr; } // 执行二进制到文本的转换 inet_ntop(rp->ai_family, ip_addr, ip_buf, sizeof(ip_buf)); printf("Connected to %s\n", ip_buf); break; }
补充说明
如果需要同时获取IP和对应的端口号,也可以使用getnameinfo()函数完成解析,无需手动判断地址族做结构强转,适合更复杂的地址解析场景。
内容的提问来源于stack exchange,提问作者packet_sniffer
相关产品推荐
相关产品推荐

