C - 获取地址信息()
C - getaddrinfo()
有人可以帮我获取 google.com 的 IP 吗?
我在这方面找不到任何好的资源。
大多数关于 C 网络编程的教程都在同一台计算机上创建一个客户端套接字和一个服务器套接字。 (我不知道在什么情况下才有意义)
beej.us 上的 none 代码对我有用。
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
int main(void)
{
struct addrinfo* res = NULL;
getaddrinfo("google.com", "443", 0, &res);
struct addrinfo* i;
for(i=res; i!=0; res=res->ai_next)
{
printf("%s\n", res->ai_addr->sa_data);
}
}
输出:
�
�
�
���$u
���$u
���$u
���"u
���"u
���"u
��� u
��� u
��� u
���&u
���&u
���&u
Segmentation fault
In This statement i
从未在循环体中被修改,并且因为它没有被初始化,它甚至从未进入循环:
for(i=res; i!=0; res=res->ai_next)
{
printf("%s\n", res->ai_addr->sa_data);
}
此外,您还遗漏了一些其他部分。以下步骤是下面链接的完整示例的一部分:
创建 struct addrinfo
的以下实例:
struct addrinfo *result = NULL;
struct addrinfo *ptr = NULL;
struct addrinfo hints;
然后初始化Winsock
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
设置hints address info
结构
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
致电getaddrinfo
dwRetval = getaddrinfo(argv[1], argv[2], &hints, &result);
if ( dwRetval != 0 ){//handle error}
现在,例如基于上面的例子,你的循环看起来像:
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {//
在完整示例(链接如下)的命令行中输入 "www.google.com" 0 类似于:
本满Windowsexample is here。 注意:代码中的错误,即 ptr->ai_cannonname 可以为空 "www.google.com" 所以更改此行以测试打电话前:
if(ptr->ai_canonname) printf("\tCanonical name: %s\n", ptr->ai_canonname);
满满的Linuxexample is here.
首先,您永远不会在循环内部修改 i
,因此您最终会陷入无限循环。您需要将循环语句更改为:
for(i=res; i!=NULL; i=i->ai_next)
关于输出,ai_addr
字段的类型是struct sockaddr *
,它是一个指向通用套接字地址结构的指针,它的sa_data
字段只是一个二进制blob该地址的数据,而不是可打印的字符串。
要正确打印这些值,您需要 inet_ntop
函数。首先,您需要检查 ai_addr->sa_family
以查看它是 IPv4 地址还是 IPv6 地址。然后,您需要将 ai_addr
转换为 IPv4 的 struct sockaddr_in *
或 IPv6 的 struct sockaddr_in6 *
,然后分别将 sin_addr
或 sin6_addr
字段传递给 inet_ntop
与地址族一起将其转换为字符串。
for(i=res; i!=NULL; i=i->ai_next)
{
char str[INET6_ADDRSTRLEN];
if (i->ai_addr->sa_family == AF_INET) {
struct sockaddr_in *p = (struct sockaddr_in *)i->ai_addr;
printf("%s\n", inet_ntop(AF_INET, &p->sin_addr, str, sizeof(str)));
} else if (i->ai_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *p = (struct sockaddr_in6 *)i->ai_addr;
printf("%s\n", inet_ntop(AF_INET6, &p->sin6_addr, str, sizeof(str)));
}
}
输出:
172.217.10.238
172.217.10.238
172.217.10.238
2607:f8b0:4006:813::200e
2607:f8b0:4006:813::200e
2607:f8b0:4006:813::200e
有人可以帮我获取 google.com 的 IP 吗?
我在这方面找不到任何好的资源。
大多数关于 C 网络编程的教程都在同一台计算机上创建一个客户端套接字和一个服务器套接字。 (我不知道在什么情况下才有意义)
beej.us 上的 none 代码对我有用。
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
int main(void)
{
struct addrinfo* res = NULL;
getaddrinfo("google.com", "443", 0, &res);
struct addrinfo* i;
for(i=res; i!=0; res=res->ai_next)
{
printf("%s\n", res->ai_addr->sa_data);
}
}
输出:
�
�
�
���$u
���$u
���$u
���"u
���"u
���"u
��� u
��� u
��� u
���&u
���&u
���&u
Segmentation fault
In This statement i
从未在循环体中被修改,并且因为它没有被初始化,它甚至从未进入循环:
for(i=res; i!=0; res=res->ai_next)
{
printf("%s\n", res->ai_addr->sa_data);
}
此外,您还遗漏了一些其他部分。以下步骤是下面链接的完整示例的一部分:
创建 struct addrinfo
的以下实例:
struct addrinfo *result = NULL;
struct addrinfo *ptr = NULL;
struct addrinfo hints;
然后初始化Winsock
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
设置hints address info
结构
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
致电getaddrinfo
dwRetval = getaddrinfo(argv[1], argv[2], &hints, &result);
if ( dwRetval != 0 ){//handle error}
现在,例如基于上面的例子,你的循环看起来像:
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {//
在完整示例(链接如下)的命令行中输入 "www.google.com" 0 类似于:
本满Windowsexample is here。 注意:代码中的错误,即 ptr->ai_cannonname 可以为空 "www.google.com" 所以更改此行以测试打电话前:
if(ptr->ai_canonname) printf("\tCanonical name: %s\n", ptr->ai_canonname);
满满的Linuxexample is here.
首先,您永远不会在循环内部修改 i
,因此您最终会陷入无限循环。您需要将循环语句更改为:
for(i=res; i!=NULL; i=i->ai_next)
关于输出,ai_addr
字段的类型是struct sockaddr *
,它是一个指向通用套接字地址结构的指针,它的sa_data
字段只是一个二进制blob该地址的数据,而不是可打印的字符串。
要正确打印这些值,您需要 inet_ntop
函数。首先,您需要检查 ai_addr->sa_family
以查看它是 IPv4 地址还是 IPv6 地址。然后,您需要将 ai_addr
转换为 IPv4 的 struct sockaddr_in *
或 IPv6 的 struct sockaddr_in6 *
,然后分别将 sin_addr
或 sin6_addr
字段传递给 inet_ntop
与地址族一起将其转换为字符串。
for(i=res; i!=NULL; i=i->ai_next)
{
char str[INET6_ADDRSTRLEN];
if (i->ai_addr->sa_family == AF_INET) {
struct sockaddr_in *p = (struct sockaddr_in *)i->ai_addr;
printf("%s\n", inet_ntop(AF_INET, &p->sin_addr, str, sizeof(str)));
} else if (i->ai_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *p = (struct sockaddr_in6 *)i->ai_addr;
printf("%s\n", inet_ntop(AF_INET6, &p->sin6_addr, str, sizeof(str)));
}
}
输出:
172.217.10.238
172.217.10.238
172.217.10.238
2607:f8b0:4006:813::200e
2607:f8b0:4006:813::200e
2607:f8b0:4006:813::200e