所述的getaddrinfo接受struct addrinfo *hints作为可被用来指定用于选择由该函数返回套接字地址的标准的第三个参数.
文档说我们可以设置ai_socktype以及ai_protocol指定我们的选择标准.但是,ai_protocol如果我们已经指定,我无法理解为什么需要ai_socktype.如果指定了这两个中的一个,那么另一个似乎是多余的.
这是我写的一些代码来试验这个.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
void getaddrinfo_demo(const char *node, const char *service,
int socktype, int protocol)
{
struct addrinfo hints, *res, *p;
int error;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = socktype;
hints.ai_protocol = protocol;
error = getaddrinfo(node, service, &hints, &res);
if (error) {
printf("Error %d: %s\n\n", error, gai_strerror(error));
return;
}
for (p = res; p != NULL; p = p->ai_next) {
struct sockaddr_in *addr = ((struct sockaddr_in *) p->ai_addr);
char ip[INET_ADDRSTRLEN];
int port = ntohs(addr->sin_port);
inet_ntop(AF_INET, &addr->sin_addr, ip, INET_ADDRSTRLEN);
printf("ip: %s; port: %d; protocol: %d\n", ip, port, p->ai_protocol);
}
printf("\n");
freeaddrinfo(res);
}
int main()
{
/* Consistent family and socktype works fine. */
getaddrinfo_demo("localhost", "http", SOCK_STREAM, IPPROTO_TCP);
getaddrinfo_demo("localhost", "http", SOCK_DGRAM, IPPROTO_UDP);
/* Inconsistent family and sock type leads to error -7. */
getaddrinfo_demo("localhost", "http", SOCK_STREAM, IPPROTO_UDP);
getaddrinfo_demo("localhost", "http", SOCK_DGRAM, IPPROTO_TCP);
}
Run Code Online (Sandbox Code Playgroud)
这是输出.
$ gcc -std=c99 -D_POSIX_SOURCE -Wall -Wextra -pedantic foo.c && ./a.out
ip: 127.0.0.1; port: 80; protocol: 6
ip: 127.0.0.1; port: 80; protocol: 6
ip: 127.0.0.1; port: 80; protocol: 17
ip: 127.0.0.1; port: 80; protocol: 17
Error -7: ai_socktype not supported
Error -7: ai_socktype not supported
Run Code Online (Sandbox Code Playgroud)
如你所知,是否ai_socktype = AF_STREAM只有ai_protocol = IPPROTO_TCP作品.指定ai_protocol = IPPROTO_UDP导致错误.有人可能会以及忽略指定ai_protocol的hints,如果我们不能通过它指定任何额外的选择标准.
那么,什么是真正的作用ai_protocol的hints?你可以给其中一个例子ai_socktype和ai_protocol两个服务于某种目的?
这些怎么样:
getaddrinfo_demo("localhost", "http", SOCK_STREAM, IPPROTO_SCTP);
getaddrinfo_demo("localhost", "imap", SOCK_STREAM, IPPROTO_TCP);
getaddrinfo_demo("localhost", "imap", SOCK_STREAM, IPPROTO_SCTP);
getaddrinfo_demo("localhost", "sbcap", SOCK_STREAM, IPPROTO_SCTP);
getaddrinfo_demo("localhost", "sbcap", SOCK_SEQPACKET, IPPROTO_SCTP);
getaddrinfo_demo("localhost", "sbcap", SOCK_STREAM, IPPROTO_TCP);
getaddrinfo_demo("localhost", "http", SOCK_DGRAM, IPPROTO_UDPLITE);
getaddrinfo_demo("localhost", "syslog-tls", SOCK_DCCP, IPPROTO_DCCP);
Run Code Online (Sandbox Code Playgroud)
哪个给你:
ip: 127.0.0.1; port: 80; protocol: 132
ip: 127.0.0.1; port: 143; protocol: 6
Error -8: Servname not supported for ai_socktype
ip: 127.0.0.1; port: 29168; protocol: 132
ip: 127.0.0.1; port: 29168; protocol: 132
Error -8: Servname not supported for ai_socktype
Error -8: Servname not supported for ai_socktype
ip: 127.0.0.1; port: 6514; protocol: 33
Run Code Online (Sandbox Code Playgroud)
因此,TCP不是唯一的流协议,并且UDP不是唯一的数据报协议(尽管DCCP有自己的,SOCK_DCCP而UDP-Lite在服务数据库中没有任何条目(有人可能认为它不需要因为UDP-Lite RFC明确表示"UDP-Lite使用由IANA分配给UDP使用的同一组端口号值")).
我们这些天在实践中并没有经常看到它,但是如果我们谈论的是API getaddrinfo(),它们必须设计得有点面向未来,这包括制作一些看似多余的东西.只有时间可以判断这些事情是否真的是多余的.在这种情况下,它不是,它恰恰相反.如果FreeBSD手册页是正确的,那么
该实现首先出现在WIDE Hydrangea IPv6协议栈工具包中.
在互联网上仍然存在关于这个协议栈的常见问题解答,我们可以从中猜测它是在1997 - 1998年左右创建的(我不是那么老,不记得这些东西,我没有看到任何其他合适的来源,如果我错了,请纠正我.和SCTP被定义在2000年当我已经与实例如上图所示,我们有SCTP使用这个API,没有任何问题.与DCCP相同的故事出现在2005-2006左右,完全符合相同的API.