从 getaddrinfo()学一点

#include <stdio.h>
#include <netdb.h>
int main()
{
struct addrinfo hints, *res;
int status;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; // IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
if ((status = getaddrinfo("www.example.com", "http", &hints, &res)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
return 1;
}
struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr;
char ip_addr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(ipv4->sin_addr), ip_addr, INET_ADDRSTRLEN);
printf("IPv4 address: %s\n", ip_addr);
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr;
char ip6_addr[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &(ipv6->sin6_addr), ip6_addr, INET6_ADDRSTRLEN);
printf("IPv6 address: %s\n", ip6_addr);
freeaddrinfo(res);
return 0;
}netdb.h 是一个 C 标准库头文件,它提供了一些函数和数据结构,用于在网络上进行主机名和服务名的解析。它包含了一些函数,如 getaddrinfo()和 gethostbyname(),可以根据主机名或服务名获取 IP 地址或主机名等信息。
netdb.h 通常与其他网络相关的头文件,如 sys/socket.h 和 netinet/in.h 一起使用,以便在网络编程中使用这些函数和数据结构。这些头文件通常在 Unix 和 Linux 系统上使用,用于实现网络应用程序。
在网络编程中,通常会使用一个名为 hints 的 addrinfo 结构体来指示 getaddrinfo()函数应该如何工作(啊?)
addrinfo 结构体在网络编程中用于存储地址信息,而 hints 结构体则用于指示 getaddrinfo()函数应该如何工作,例如指定套接字类型、地址族以及其他选项。res 指针将用于存储 getaddrinfo()函数返回的结果,即主机名和服务名相关联的地址信息。由于 getaddrinfo()函数返回的是一个 addrinfo 类型的链表,因此 res 变量实际上是一个指向链表头部的指针。
在这个例子中,&hints 是一个指向 addrinfo 类型的结构体 hints 的指针,sizeof(hints)返回 hints 结构体的大小,即需要设置的字节数。因此,这句话的含义是将 hints 结构体中的所有字节都设置为 0,以确保结构体中所有的成员都被初始化为默认值。这是一种常见的编程技巧,可以避免在使用结构体时出现未定义的行为。
memset()函数是一个 C 标准库函数,用于将一块内存中的每个字节都设置为指定的值。它的原型为
void *memset(void *s, int c, size_t n) 其中 s 是指向要设置的内存块的指针,c是要设置的值,n是要设置的字节数。
AF_UNSPEC 是一个常量,它定义在 sys/socket.h 头文件中,表示"未指定地址族"。在网络编程中,地址族用于指定使用的协议族,例如 IPv4 或 IPv6。当指定 AF_UNSPEC 时,系统会自动选择合适的地址族。
fprintf、sprintf 和 printf 的区别在于输出的目标和方式。
• printf 函数将格式化的字符串输出到标准输出流 stdout 中,即输出到终端屏幕上。
• fprintf 函数将格式化的字符串输出到指定的输出流中,例如标准错误流 stderr 或文件流。
• sprintf 函数将格式化的字符串输出到一个字符数组中,而不是输出到流中。
gai_strerror()函数用于将 getaddrinfo()函数返回的错误码转换成一个可读的错误消息。
addrinfo 结构体中的 ai_addr 成员是一个指向通用的 sockaddr 类型结构体的指针,它可以存储 IPv4 或 IPv6 地址信息。 要获取 IPv4 地址信息,因此需要将 ai_addr 指针强制转换为指向 sockaddr_in 类型的指针。sockaddr_in 结构体是一个专门用于存储 IPv4 地址信息的结构体,它包含了 IPv4 地址和端口号等信息。
ip_addr 的字符数组,用于存储 IPv4 地址的字符串表示形式。
INET_ADDRSTRLEN 是一个常量,定义在头文件 netinet/in.h 中,它表示 IPv4 地址的最大长度,通常为 16 个字符。因此,ip_addr 数组的大小被设置为 INET_ADDRSTRLEN,可以确保存储 IPv4 地址的字符串表示形式所需的空间。
这句代码使用 inet_ntop()函数将 IPv4 地址从二进制格式转换为点分十进制格式,并将转换后的字符串存储在名为 ip_addr 的字符数组中。
具体来说,inet_ntop()函数是一个标准库函数,它的原型为:
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); 其中,af 表示地址族,src 是一个指向包含二进制格式地址的结构体的指针,dst 是一个指向用于存储转换后地址的字符数组的指针,size 是该字符数组的大小。
在这个例子中,inet_ntop()函数的第一个参数 AF_INET 表示要转换的地址族为 IPv4,第二个参数&(ipv4->sin_addr)表示要转换的二进制格式地址存储在 sockaddr_in 结构体中的 sin_addr 成员中,第三个参数 ip_addr 表示转换后的点分十进制格式地址将存储在该字符数组中,第四个参数 INET_ADDRSTRLEN 表示该字符数组的最大大小为16个字节。