作者:kaining_huang_750 | 来源:互联网 | 2022-12-02 17:09
1> Remy Lebeau..:
这些gethostbyname()
和gethostbyaddr()
函数在大多数平台上都已弃用,并且它们不实现对IPv6的支持.IPv4已达到极限,现在世界已经转向IPv6一段时间了.分别使用getaddrinfo()
和getnameinfo()
代替.
回答你的问题:
A. getaddrinfo()
并且getnameinfo()
可用于客户端和服务器一样,就像gethostbyname()
和gethostbyaddr()
即可.它们只是主机/地址解析功能,如何使用已解析的值取决于调用应用程序来决定.
B.客户端代码使用getaddrinfo()
看起来像这样:
int OpenConnection(const char *hostname, int port)
{
int sd, err;
struct addrinfo hints = {}, *addrs;
char port_str[16] = {};
hints.ai_family = AF_INET; // Since your original code was using sockaddr_in and
// PF_INET, I'm using AF_INET here to match. Use
// AF_UNSPEC instead if you want to allow getaddrinfo()
// to find both IPv4 and IPv6 addresses for the hostname.
// Just make sure the rest of your code is equally family-
// agnostic when dealing with the IP addresses associated
// with this connection. For instance, make sure any uses
// of sockaddr_in are changed to sockaddr_storage,
// and pay attention to its ss_family field, etc...
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
sprintf(port_str, "%d", port);
err = getaddrinfo(hostname, port_str, &hints, &addrs);
if (err != 0)
{
fprintf(stderr, "%s: %s\n", hostname, gai_strerror(err));
abort();
}
for(struct addrinfo *addr = addrs; addr != NULL; addr = addr->ai_next)
{
sd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (sd == -1)
{
err = errno;
break; // if using AF_UNSPEC above instead of AF_INET/6 specifically,
// replace this 'break' with 'continue' instead, as the 'ai_family'
// may be different on the next iteration...
}
if (connect(sd, addr->ai_addr, addr->ai_addrlen) == 0)
break;
err = errno;
close(sd);
sd = -1;
}
freeaddrinfo(addrs);
if (sd == -1)
{
fprintf(stderr, "%s: %s\n", hostname, strerror(err));
abort();
}
return sd;
}
2> paulsm4..:
我总是使用gethostbyname(),因为"永远".它始终有效,它继续工作,而且"更简单".
getaddrinfo()是更新的函数:
http://man7.org/linux/man-pages/man3/getaddrinfo.3.html
getaddrinfo()函数将gethostbyname(3)和getservbyname(3)函数提供的功能组合到一个接口中,但与后面的函数不同,getaddrinfo()是可重入的,并允许程序消除IPv4与IPv6的依赖关系.
我知道getaddrinfo()更强大,更高效,更安全:你不应该使用gethostbyname()
附录:
在回答您的具体问题时:
A] getaddrinfo()
优先gethostbyname()
于查找主机名的IP地址; "客户"或"服务器".
B]问:我如何修改提示结构和函数参数?
答:"提示"看起来不错,但我可能会将端口修改为NULL.
这是一个完整的例子:
https://www.kutukupret.com/2009/09/28/gethostbyname-vs-getaddrinfo/
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
struct addrinfo hints, *res, *p;
int status;
char ipstr[INET6_ADDRSTRLEN];
if (argc != 2) {
fprintf(stderr, "Usage: %s hostname\n", argv[0]);
return 1;
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
hints.ai_socktype = SOCK_STREAM;
if ((status = getaddrinfo(argv[1], NULL, &hints, &res)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 2;
}
for(p = res;p != NULL; p = p->ai_next) {
void *addr;
if (p->ai_family == AF_INET) {
return 1;
} else {
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &(ipv6->sin6_addr);
/* convert the IP to a string and print it: */
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
printf("Hostname: %s\n", argv[1]);
printf("IP Address: %s\n", ipstr);
}
}
freeaddrinfo(res); // free the linked list
return 0;
}
@jiveturkey`getservbyname()`只是将符号"服务名称"(如`http`或`ftp`)映射到端口号的函数,它与您运行的是客户端还是服务器无关.它可能只是这样命名,因为在Unix系统上它读取`/ etc/services`来指定映射.
不,我想传达的印象就是`getaddrinfo()`是将主机名映射到IP的"更好"方式,而不是经典的`gethostbyname()`.这两个功能都适用于*EITHER*客户端或服务器.