getaddrinfo删除最后一个字符

时间:2013-01-26 01:16:04

标签: c sockets localhost character getaddrinfo

int print_socket_info(int sock_fd, struct sockaddr_in *sin, short protocol){
    char dbg[INET_ADDRSTRLEN];
    char *famstr;
inet_ntop(protocol, &(sin->sin_addr), dbg, INET_ADDRSTRLEN);
printf("============ SOCKET INFORMATION =============\n");
printf("!** socket: %d\n", sock_fd);
printf("!** info->ai_addr: sockaddr_in(\n");
famstr = fam2str(sin->sin_family);
printf("!**     sin_family:    %s\n", famstr);
printf("!**     sin_port:      %d\n", ntohs(sin->sin_port));
printf("!**     sin_addr:      in_addr( s_addr : '%s' )\n", dbg);
printf("!**)\n");
printf("=============================================\n");
return 1;
}

char *fam2str(int fam){
switch (fam){
    case AF_INET:
        return "AF_INET";
    case AF_INET6:
        return "AF_INET6";
    case AF_UNSPEC:
        return "AF_UNSPEC";
    default:
        return "(UNKNOWN)";
    }
    return "(UNKNOWN)";
}

如果我传入hint.ai_addr(忽略信息 - > ...那是字符串的一部分),就像这样:

print_socket_info(sock, (struct sockaddr_in *)hint.ai_addr, protocol);

...然后我打印出以下内容......

============ SOCKET INFORMATION =============
!** socket: 3
!** info->ai_addr: sockaddr_in(
!**     sin_family:    AF_INET6
!**     sin_port:      8081
!**     sin_addr:      in_addr( s_addr : '::1' )
!**)
=============================================

...信息正确打印出来。接下来我调用函数:

res =  getaddrinfo(target_host, target_port, &hint, &info);

到目前为止我没有收到任何错误。现在,我遍历链表:

struct addrinfo *rp;
for (rp = info; rp != NULL; rp = rp->ai_next){
    printf("==> Another element.\n");
    print_socket_info(sock, (struct sockaddr_in *) rp->ai_addr, protocol);
}

...我只打印了一个元素:

============ SOCKET INFORMATION =============
!** socket: 3
!** info->ai_addr: sockaddr_in(
!**     sin_family:    AF_INET6
!**     sin_port:      8081
!**     sin_addr:      in_addr( s_addr : '::' )
!**)
=============================================

......当然,这会对bind()造成严重破坏。为什么地址缩短了?

其他奇怪的事情:如果我传入127.0.0.1并使用AF_INET4,则整个程序中的地址都会被维护(我只得到一个结果,但绑定仍然失败)。

有什么想法吗?提前谢谢。

1 个答案:

答案 0 :(得分:1)

您的print_socket_info功能错误。如果采用struct sockaddr_in *(IPv4套接字地址结构),但它意味着支持IPv4和IPv6。

您必须声明print socket_info采用通用struct sockaddr *(任何类型的套接字地址)。为了更好地衡量:将sin参数重命名为sa以指示它是通用类型,而不是struct sockaddr_in类型。然后,在函数内部,检查sin->sin_family以查找实际系列的内容,然后根据需要sinstruct sockaddr_in *struct sockaddr_in6转换为

现有功能中发生的事情是,您只需将整个功能视为struct sockaddr_in *,并将以下结果(至少在Linux上):

  • 检查sin_family是正常的,因为无论是struct sockaddr_in还是struct sockaddr_in6还是{{1},系列保证与所有类型的sockaddrs在结构中的偏移量相同对于UNIX域套接字或所有其他模糊地址系列的sockaddr结构也是如此。
  • 检查struct sockaddr_un时,您很幸运,因为sin_port中的sin_port碰巧位于struct sockaddr_in sin6_port的结构中}}。
  • 如果对struct sockaddr_in6不起作用,因为对于IPv4,sin_addr紧跟在sin_addr结构中,但对于IPv6,在该位置找到了其他一些字段(即, sin_port)。 sin6_flowinfo在其他地方。

sin6_addr的另一个问题是你的字符串缓冲区只有足够的空间用于IPv4地址字符串,因为它声明的长度为print_socket_info,这对于IPv6来说太短了(对于IPv6你需要{ {1}}。函数不需要参数INET_ADDRSTRLEN。这些信息已经嵌入到sockaddr中。

INET6_ADDRSTRLEN