首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用getaddrinfo选择服务器套接字地址?

如何使用getaddrinfo选择服务器套接字地址?
EN

Stack Overflow用户
提问于 2016-08-18 19:34:19
回答 1查看 1.2K关注 0票数 1

我想创建一个TCP服务器应用程序,它允许用户选择绑定调用中使用的本地地址。用户可能会提供主机名或IP地址的文本表示,因此我考虑使用getaddrinfo函数将文本表示转换为一个或多个sockaddr结构(必要时执行名称查找)。

现在我的问题是: getaddrinfo函数似乎不适合我的需要,因为它要求在提示结构中设置AI_PASSIVE标志,以便获得可以用于绑定调用的套接字地址。但是如果我使用AI_PASSIVE,就不能再使用nodename参数了,这就违背了让用户选择本地地址的整个目的。如果我不提供AI_PASSIVE,getaddrinfo将只返回那些可以用于connect、sendto和sendmsg调用的地址,但是可能有一些地址可以用于绑定,而不是用于连接、sendto或sendmsg调用,这些地址将被省略。请参阅关于getaddrinfo/freeaddrinfo函数的POSIX规范。

为了澄清我的需求,下面是我试图创建的应用程序的草图:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>

int main(int argc, char **argv)
{
    if (argc != 3) {
        fprintf(stderr, "Usage: %s address port\n", argv[0]);
        return EXIT_FAILURE;
    }

    struct addrinfo hints = {0};
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;

    struct addrinfo *result;
    /* The next line won't work as intended! It will behave as if the
    AI_PASSIVE flag was not set. */
    if (getaddrinfo(argv[1], argv[2], &hints, &result) != 0) {
        perror("getaddrinfo");
        return EXIT_FAILURE;
    }

    /* Iterate result list */
    int sfd;
    struct addrinfo *rp = result;
    do {
        sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        if (sfd == -1)
            continue;

        if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
            break; /* Success */

        close(sfd);
        rp = rp->ai_next;
    } while (rp != NULL);

    freeaddrinfo(result);

    if (rp == NULL) { /* No address succeeded */
        fprintf(stderr, "Could not bind\n");
        return EXIT_FAILURE;
    }

    /* ... use socket bound to sfd ... */

    close(sfd);

    return EXIT_SUCCESS;
}

实际上,我有几个关于这个话题的问题。首先,为什么在使用AI_PASSIVE标志时禁止nodename参数?目的是什么?对我来说没有任何意义。是否有任何方法(最好是POSIX-一致性)来找到我可以绑定的本地地址,以及与给定主机名或IP地址对应的本地地址?如果给定的节点名对应于本地地址,并且没有设置AI_PASSIVE,那么是否会有getaddrinfo返回的不能用于绑定的地址?或者更糟糕的是,是否有只适合绑定的地址,在这种情况下不会返回呢?

相关(未得到满意答复):如果指定了节点名,则被动忽略?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-08-18 22:28:48

我同意参考问题没有得到令人满意的答复,海事组织的整个特点没有得到明确的说明。

我相信AI_PASSIVE旗子的名字不对。它应该被称为类似AI_ANY_ADDRESS的东西。它的意思只是“给我一个令牌,我可以用来绑定到这个系统上的任何节点地址(地址家族中,等等)”,这样您就不必硬编码INADDR_ANYIN6ADDR_ANY_INIT了。因此,如果您提供一个节点名称参数,那么您就删除了AI_PASSIVE的要点。你是说“这是我要绑定的地址”。

在实践中,这一切都很好,因为bindconnect所接受的地址结构在所有情况下都是基本相同的(除了不能对特殊的“任意”地址进行connect )。这就是为什么--当您指定节点名称时--不管您是否指定AI_PASSIVE。您将获得针对指定名称/地址的bindconnect调用的适当参数。

获取“地址信息”并不意味着bindconnect会成功。您可以成功地获得一个您不能bind到的地址--因为它不是本地计算机的地址--或者也因为其他原因。(很明显,connect也可能因为许多原因而失败-在该地址上可能没有应答机器,或者没有服务器监听端口等等)。

如果您提供一个非IP地址的节点名称,并且名称解析提供不同家族中的多个IP地址(这些地址在本地计算机上都可用),则应该能够对所有这些地址进行bind

因此,底线是:如果您希望允许用户指定地址,只需将其提供给getaddrinfo即可。返回的地址(如果有的话)应该可以在bind调用中使用。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39026202

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档