c - 当已经指定了 ai_socktype 时调用 getaddrinfo() 时 ai_protocol 可以在提示中起到什么额外的作用?

标签 c linux sockets

getaddrinfo接受 struct addrinfo *hints 作为第三个参数,可用于指定选择要由该函数返回的套接字地址的标准。

文档说我们可以设置 ai_socktype 以及 ai_protocol 来指定我们的选择标准。但是,如果我们已经指定了 ai_socktype,我无法理解为什么需要 ai_protocol。如果指定了这两者之一,那么另一个似乎是多余的。

这是我编写的一些代码来对此进行试验。

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

这是输出。

$ 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

如您所见,如果 ai_socktype = AF_STREAM,则只有 ai_protocol = IPPROTO_TCP 有效。指定 ai_protocol = IPPROTO_UDP 会导致错误。如果我们不能通过它指定任何额外的选择标准,那么也可以省略在 hints 中指定 ai_protocol

那么 ai_protocolhints 中的真正作用是什么?您能否举例说明 ai_socktypeai_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);

哪个给你:

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

所以 TCP 不是唯一的流协议(protocol),UDP 也不是唯一的数据报协议(protocol)(尽管 DCCP 有自己的 SOCK_DCCP 并且 UDP-Lite 在服务数据库中没有任何条目(有人可能会争辩说它不需要,因为 UDP-Lite RFC 明确表示“UDP-Lite 使用由 IANA 分配给 UDP 使用的同一组端口号值”)。

现在我们在实践中并不经常看到它,但是如果我们谈论像 getaddrinfo() 这样的 API,它们必须被设计成面向 future 的,这包括做一些看似多余的事情。只有时间才能证明这些东西是否真的是多余的。在这种情况下不是,恰恰相反。如果FreeBSD man page是正确的,那么

The implementation first appeared in WIDE Hydrangea IPv6 protocol stack kit.

仍然存在 FAQ关于互联网上的这个协议(protocol)栈,从中我们可以猜测它是在1997--1998年左右创建的(我还没有那么大的内存力,我也没有看到任何其他合适的来源,所以请纠正我'我错了)。和 SCTP was defined 2000 年。正如我在上面的示例中所展示的,我们使用此 API 的 SCTP 没有任何问题。 2005--2006 年左右出现的与 DCCP 相同的故事,非常适合相同的 API。

关于c - 当已经指定了 ai_socktype 时调用 getaddrinfo() 时 ai_protocol 可以在提示中起到什么额外的作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39474941/

相关文章:

连接到本地虚拟机

c - 是否可以通过 select() 在无限循环中使用 nanosleep?

c - 需要解释我们如何使用递归二进制搜索算法搜索数学函数的零点

c++ - C/C++ : How to use the do-while(0); construct without compiler warnings like C4127?

c - 如何在两个进程之间用管道发送整数!

java - Android连接到java服务器套接字,但服务器套接字没有接收数据

c - 没有出现段错误

linux - 处理数百万个文件的 ext 性能

linux - sudo: apt-get: 命令未找到 Linux 服务器

c - select() 和 C 上带有动态缓冲区的非阻塞 recv