这是一个简单的程序,展示了我们在编写套接字程序时通常如何将struct sockaddr *
强制转换为struct sockaddr_in *
或struct sockaddr_in6 *
。
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int main()
{
struct addrinfo *ai;
printf("sizeof (struct sockaddr): %zu\n", sizeof (struct sockaddr));
printf("sizeof (struct sockaddr_in): %zu\n", sizeof (struct sockaddr_in));
printf("sizeof (struct sockaddr_in6): %zu\n", sizeof (struct sockaddr_in6));
if (getaddrinfo("localhost", "http", NULL, &ai) != 0) {
printf("error\n");
return EXIT_FAILURE;
}
if (ai->ai_family == AF_INET) {
struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
printf("IPv4 port: %d\n", addr->sin_port);
} else if (ai->ai_family == AF_INET6) {
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr;
printf("IPv6 port: %d\n", addr->sin6_port);
}
return 0;
}
Beej's Guide to Network Programming在第10页也推荐了这个方法。
为了处理struct sockaddr,程序员创建了一个并行结构:struct sockaddr_in(“in”代表“Internet”),用于IPv4。
这是重要的一点:可以将指向struct sockaddr_in的指针转换为指向struct sockaddr的指针,反之亦然。因此,即使connect()需要一个struct sockaddr*,你仍然可以使用struct sockaddr_in,并在最后一刻进行强制类型转换!
但从另一个问题的讨论中,似乎这只是一个hack,不符合C标准的有效C代码。
特别是请参见AnT的答案,其中提到:
至于在struct sockaddr *、struct sockaddr_in *和struct sockaddr_in6 *之间进行转换的常见技巧——这些只是hack,与C语言无关。它们在实践中起作用,但就C语言而言,该技术是无效的。
因此,如果我们用于套接字编程的这种技术(并且也被书籍推荐)是无效的,那么重写上述代码的有效C代码方式是什么?