简体   繁体   English

当已指定 ai_socktype 时,在调用 getaddrinfo() 时,ai_protocol 可以在提示中提供什么额外用途?

[英]What additional purpose can ai_protocol serve in hints while calling getaddrinfo() when ai_socktype is already specified?

The getaddrinfo accepts struct addrinfo *hints as the third argument which can be used to specify the criteria for selecting socket addresses to be returned by this function. getaddrinfo接受struct addrinfo *hints作为第三个参数,该参数可用于指定选择此函数返回的套接字地址的标准。

The documentation says that we could set ai_socktype as well as ai_protocol to specify our selection criteria.文档说我们可以设置ai_socktypeai_protocol来指定我们的选择标准。 However, I am unable to understand why ai_protocol is required if we already specify ai_socktype .然而,我无法理解为什么ai_protocol如果我们已经指定需要ai_socktype If one of these two is specified, then the other seems redundant.如果指定了这两个中的一个,那么另一个似乎是多余的。

Here is some code that I wrote to experiment with this.这是我写的一些代码来试验这个。

#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);
}

Here is the output.这是输出。

$ 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

As you can see if ai_socktype = AF_STREAM , then only ai_protocol = IPPROTO_TCP works.如您所见,如果ai_socktype = AF_STREAM ,则只有ai_protocol = IPPROTO_TCP有效。 Specifying ai_protocol = IPPROTO_UDP leads to error.指定ai_protocol = IPPROTO_UDP会导致错误。 One might as well omit specifying ai_protocol in the hints if we can't specify any additional selection criteria via it.如果我们不能通过ai_protocol指定任何额外的选择标准,我们ai_protocolhints省略指定ai_protocol

So what is really the role of ai_protocol in hints ?那么ai_protocolhints真正作用是什么? Can you give an example in which ai_socktype and ai_protocol both serve some purpose?你能举一个例子,说明ai_socktypeai_protocol都有什么用途吗?

How about these:这些怎么样:

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);

Which give you:这给你:

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

So TCP is not the only streaming protocol, as well as UDP is not the only datagram protocol (although DCCP has its own SOCK_DCCP and UDP-Lite doesn't have any entries in the services DB (one might argue that it doesn't need to as UDP-Lite RFC explicitly says that "UDP-Lite uses the same set of port number values assigned by the IANA for use by UDP")).所以 TCP 不是唯一的流协议,UDP 也不是唯一的数据报协议(尽管 DCCP 有自己的SOCK_DCCP并且 UDP-Lite 在服务 DB 中没有任何条目(有人可能会争辩说它不需要UDP-Lite RFC明确表示“UDP-Lite 使用 IANA 分配的一组相同的端口号值供 UDP 使用”))。

We don't see it often in practice these days, but if we're talking about APIs like getaddrinfo() , they have to be designed to be somewhat future-proof, and that includes making some seemingly redundant things.这些天我们在实践中并不经常看到它,但是如果我们谈论像getaddrinfo()这样的 API,它们必须被设计成有点面向未来,其中包括制作一些看似多余的东西。 Only time can tell whether these things really are redundant, or not.只有时间才能证明这些东西是否真的是多余的。 In this case it's not, it's exactly the opposite.在这种情况下,事实并非如此,恰恰相反。 If FreeBSD man page is correct, then如果FreeBSD 手册页正确,则

The implementation first appeared in WIDE Hydrangea IPv6 protocol stack kit.该实现首先出现在 WIDE Hydrangea IPv6 协议栈套件中。

There is still present an FAQ about this protocol stack on the Internet, from which we can guess that it was created around 1997--1998 (I'm not that old to remember such things and I don't see any other appropriate source, so correct me if I'm wrong).互联网上仍然有关于这个协议栈的常见问题解答,从中我们可以猜测它是在 1997--1998 年左右创建的(我还没有那么老记得这些事情,我没有看到任何其他合适的来源,所以如果我错了,请纠正我)。 And SCTP was defined in 2000. As I've shown with examples above, we have SCTP using this API without any problems. SCTP 是在 2000年定义的。正如我在上面的例子中所展示的,我们使用这个 API 的 SCTP 没有任何问题。 Same story with DCCP that appeared around 2005--2006, fits into the same API perfectly.与 2005--2006 年左右出现的 DCCP 相同的故事,完全适合相同的 API。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM