gpt4 book ai didi

c - getaddrinfo 删除最后一个字符

转载 作者:行者123 更新时间:2023-11-30 15:52:18 27 4
gpt4 key购买 nike

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,那么该地址将在整个程序中保留(尽管我只得到一个结果,但绑定(bind)仍然失败)。

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

最佳答案

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

您必须声明print socket_info以获取通用struct sockaddr *(任何类型的套接字地址)。为了更好的措施:将 sin 参数重命名为 sa 以表明它是泛型类型,而不是 struct sockaddr_in 类型。然后,在函数内部,检查 sin->sin_family 以找出实际的系列,并继续将 sin 转换为 struct sockaddr_in *struct sockaddr_in6(视情况而定)。

现有函数中发生的情况是,您只是在整个函数中将其视为 struct sockaddr_in * ,结果如下(至少在 Linux 上):

  • 检查 sin_family 是可以的,因为可以保证该系列在所有类型的 sockaddrs 的结构中具有相同的偏移量,无论是 struct sockaddr_in 还是 struct sockaddr_in6 甚至用于 UNIX 域套接字的 struct sockaddr_un 或用于所有其他晦涩地址系列的 sockaddr 结构。
  • 你很幸运在检查 sin_port 时逃脱了它,因为 struct sockaddr_in 中的 sin_port 恰好位于结构中的相同偏移处作为struct sockaddr_in6中的sin6_port
  • 如果对 sin_addr 不起作用,因为对于 IPv4,sin_addr 紧接在结构中的 sin_port 之后,但对于 IPv6,其他一些字段可在该位置找到(即 sin6_flowinfo)。 sin6_addr 在其他地方。

print_socket_info 的另一个问题是您的字符串缓冲区只有足够的空间容纳 IPv4 地址字符串,因为它声明的长度 INET_ADDRSTRLEN 对于 IPv6 来说太短了(对于 IPv6,您需要 INET6_ADDRSTRLEN。并且该函数不需要采用参数 protocol。此信息已嵌入到 sockaddr 中。

int print_socket_info(int sock_fd, struct sockaddr *sa){
char dbg[INET6_ADDRSTRLEN]; /* the larger of the two sizes */
char *famstr;
unsigned short port;

switch (sa->sa_family):
case AF_INET4:
inet_ntop(AF_INET4, &(((struct sockaddr_in *)sa)->sin_addr), dbg, sizeof(dbg));
port = ((struct sockaddr_in *)sa)->sin_port;
break;
case AF_INET6:
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), dbg, sizeof(dbg));
port = ((struct sockaddr_in6 *)sa)->sin6_port;
break;
default:
strcpy(dst, "UNKNOWN");
port = 0;
}
printf("============ SOCKET INFORMATION =============\n");
printf("!** socket: %d\n", sock_fd);
printf("!** info->ai_addr: sockaddr_in(\n");
famstr = fam2str(sa->sa_family);
printf("!** sa_family: %s\n", famstr);
printf("!** sin[6]_port: %d\n", ntohs(port));
printf("!** sin[6]_addr: in_addr( s_addr : '%s' )\n", dbg);
printf("!**)\n");
printf("=============================================\n");
return 1;
}

关于c - getaddrinfo 删除最后一个字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14532785/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com