草庐IT

c - getaddrinfo 和 INADDR_ANY

coder 2023-09-18 原文

找了几个小时,还是一头雾水。根据我的发现,INADDR_ANY 旨在指定套接字将接受与分配给服务器的任何地址的连接。然而,以下导致客户端只能从同一台机器连接到 localhost:7777

addrinfo hints;
addrinfo* result;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(INADDR_ANY, "7777", &hints, &result);

SOCKET listenSocket = INVALID_SOCKET;
listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);

bind(listenSocket, result->ai_addr, (int)result->ai_addrlen);

我找到的唯一解决方案是将 INADDR_ANY 更改为机器的本地 IP:

getaddrinfo("192.168.0.105", "7777", &hints, &result);

我需要了解 INADDR_ANY 的工作原理,因为我觉得我只是以某种方式滥用了它。任何帮助将不胜感激。

最佳答案

INADDR_ANY 与您的问题无关。

getaddrinfo() 的第一个参数是一个 const char * 指定 IP 地址或主机名。但是 INADDR_ANY 是一个整数。您的代码甚至可以编译的唯一原因是因为 INADDR_ANY 被定义为整数常量 0,这是唯一允许分配给指针的整数常量。因此,您实际上是将 NULL 传递给第一个参数。在这种情况下这很好,因为这正是您所需要的。

您没有考虑到的是 getaddrinfo() 返回一个地址的链接列表,其中可能包含多个地址,尤其是如果您使用 AF_UNSPEC。使用该系列会告诉 getaddrinfo() 它可以为 IPv4 和 IPv6 返回地址。但是您只使用列表中的第一个地址,它恰好对应于 localhost(IPv4 中的 127.0.0.1,IPv6 中的::1)。

对于服务器,您应该为输出列表中的每个地址创建并绑定(bind)一个单独的监听套接字。这将使您绑定(bind)到所有符合您传递给 getaddrinfo() 的条件的地址,例如:

addrinfo hints = {};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;

addrinfo* result;

if (getaddrinfo(NULL, "7777", &hints, &result) == 0)
{
    for (addrinfo *addr = result; addr != NULL; addr = addr->ai_next)
    {
        SOCKET listenSocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
        if (listenSocket != INVALID_SOCKET)
        {
            bind(listenSocket, addr->ai_addr, (int)addr->ai_addrlen);
            listen(listenSocket, ...);
            // store listenSocket in a list for later use... 
        }
    }
    freeaddrinfo(result);
}

// use listening sockets as needed... 

或者,正如 Sam V 在评论中提到的,您可以跳过 getaddrinfo(),在这种情况下它并不能真正帮助您。您可以直接创建和绑定(bind) 2 个套接字,一个用于 IPv4,一个用于 IPv6:

SOCKET listenSocket4 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket4 != INVALID_SOCKET)
{
    sockaddr_in addr = {};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(7777);
    addr.sin_addr.s_addr = INADDR_ANY;

    bind(listenSocket4, (sockaddr*) &addr, sizeof(addr));
    listen(listenSocket4, ...);
}

SOCKET listenSocket6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket6 != INVALID_SOCKET)
{
    sockaddr_in6 addr = {};
    addr.sin6_family = AF_INET6;
    addr.sin6_port = htons(7777);
    addr.sin6_addr = in6addr_any;

    bind(listenSocket6, (sockaddr*) &addr, sizeof(addr));
    listen(listenSocket6, ...);
}

// use listening sockets as needed... 

或者更好的是,创建并绑定(bind)一个 dual-stack支持 IPv4 和 IPv6 的套接字:

SOCKET listenSocket = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket != INVALID_SOCKET)
{
    BOOL off = FALSE;
    setsockopt(listenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&off, sizeof(off));

    sockaddr_in6 addr = {};
    addr.sin6_family = AF_INET6;
    addr.sin6_port = htons(7777);
    addr.sin6_addr = in6addr_any;

    bind(listenSocket, (sockaddr*) &addr, sizeof(addr));
    listen(listenSocket, ...);
}

// use listening socket as needed... 

关于c - getaddrinfo 和 INADDR_ANY,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46626660/

有关c - getaddrinfo 和 INADDR_ANY的更多相关文章

  1. ruby - Mechanize 的 getaddrinfo 错误 - 2

    我编写了一个脚本,它将遍历我们数据库中的所有客户,验证他们的网站URL是否有效,并尝试在他们的主页上找到一个Twitter链接。我们有超过10,000个URL需要验证。在url验证一小部分后,我们开始收到每个URL的getaddrinfo错误。这是抓取单个URL的代码副本:defscrape_url(url)url_found=falsetwitter_name=nilbeginagent=Mechanize.newdo|a|a.follow_meta_refresh=trueendagent.get(normalize_url(url))do|page|url_found=truet

  2. ruby - Net::HTTP SocketError: getaddrinfo: nodename 或 servname provided, or not known - 2

    我用谷歌搜索了这个问题并浏览了关于这个问题的相关帖子。我认为这不是Rails/Ruby问题,但不确定下一步该怎么做。irb(main):007:0>Net::HTTP.get_response("http://www.apple.com","")SocketError:getaddrinfo:nodenamenorservnameprovided,ornotknownfrom/Users/dan/.rbenv/versions/2.2.3/lib/ruby/2.2.0/net/http.rb:879:in`initialize'否则没有网络问题。apple.com在浏览器中加载正常。这

  3. ruby-on-rails - `allow_any_instance_of` 模拟不在范围内工作 - 2

    我的mock只有在如下所示的beforeblock中时才有效。这只是我对我的问题的快速而肮脏的表述。从字面上看,当我将行从beforeblock移动到doesnotquack断言时,它停止模拟:(describe'Ducks',type::featuredobeforedo...allow_any_instance_of(Duck).toreceive(:quack).and_return('bark!')visitanimal_farm_pathendcontext'isanoddduck'it'doesnotquack'doexpect(Duck.new.quack).toeq('

  4. ruby-on-rails - .present 的 Rails 习语?和.any? - 2

    是否有Rails/Ruby习惯用法来检查可枚举值是否存在且是否具有非nil值?如果我尝试执行nil.any?,我会出错,所以我总是必须执行iffoo&&foo.any?。 最佳答案 可以使用ActiveSupport提供的try方法:obj.try(:any?)如果obj.nil?这将评估为nil或如果obj是空集合则评估为false,因此在这两种情况下,它都会在bool上下文中求值为假值。 关于ruby-on-rails-.present的Rails习语?和.any?,我们在Stack

  5. ruby - Chef 11 : any way to turn attributes into a ruby hash? - 2

    我在chef属性中为我的服务生成一个配置。但是,在某些时候,我需要将属性混搭转换为简单的ruby​​散列。这曾经在Chef10中运行良好:node.myapp.config.to_hash但是,从Chef11开始,这不起作用。只有属性的顶层被转换为散列,然后嵌套值仍然是不可变的混搭对象。修改它们会导致如下错误:Chef::Exceptions::ImmutableAttributeModification------------------------------------------------Nodeattributesareread-onlywhenyoudonotspecif

  6. ruby-on-rails - 为什么我会收到此 Passenger 错误 Could not find rake-0.9.2.2 in any of the sources? - 2

    我刚刚创建了一个新的空Rails应用程序,它几乎是空的。我创建它只是为了找出问题所在,但我收到了以下错误。我正在使用Rails3.1.0和Ruby1.9.2Errormessage:Couldnotfindrake-0.9.2.2inanyofthesources(Bundler::GemNotFound)Exceptionclass:PhusionPassenger::UnknownError所以我将rake-0.9.2.2添加到Gemfile并运行bundle,但我仍然收到相同的错误消息。我不知道问题出在哪里,我什至尝试打开Rails日志文件,但里面什么也没有。我尝试了很多次以不同

  7. ruby-on-rails - object.count 返回 0。但是 object.any?返回真。发生了什么? - 2

    @card.submissions返回:]>@card.submissions.any?返回true。@card.submissions.count返回0。我要实现的是:if@card.submissions.any?render@card.submissionsend 最佳答案 看起来Submission是一个新记录(因为id是nil)。如果它是新的,它还没有进入数据库。count对数据库进行SQL调用以确定行数,因此正确地返回零。any?返回true,因为集合中有一个对象。如果您尝试@card.submissions.to_a.

  8. ruby - Rspec any_instance.stub 为 nil :NilClass exception 引发未定义的方法 `any_instance_recorder_for' - 2

    这是我正在测试的包含在Foo.rb中的类:classFoodefbarreturn2endend这是Foo_spec.rb中包含的我的测试:require"./Foo.rb"describe"Foo"dobefore(:all)doputs"#{Foo==nil}"Foo.any_instance.stub(:bar).and_return(1)endit"shouldpassthis"dof=Foo.newf.bar.shouldeq1endend我得到以下输出:falseFFailures:1)FooShouldpassthisFailure/Error:Foo.any_insta

  9. ruby - 如何避免使用 allow_any_instance_of? - 2

    假设我们有以下代码:classAdefcreate_serveroptions={name:NameBuilder.new.build_name}do_some_operations(options)endend为了测试这些方法,我曾经使用allow_any_instance_of:it'doesoperations'doallow_any_instance_of(NameBuilder).toreceive(:build_name)#testbodyend但是文档建议我们不要使用它becauseofseveralreasons.那么如何避免allow_any_instance_of呢

  10. ruby - 正则表达式 : Any characters except sequence - 2

    [^abc]Anysinglecharacterexcept:a,b,orc但是我如何为除序列abc之外的任何字符制作正则表达式所以,类似的东西"Helloabcawesomeworld".scan/[^(abc)]+/将返回“Hello”和“awesomeworld”。PS:而且不是分割字符串 最佳答案 这叫做lookaround,在您的情况下,您需要使用负前瞻。我不确定Ruby中的确切语法,但(?!abc)中的某些内容可能会起作用。请注意,lookaround不会消耗任何输入,因此您需要在其后跟任何您想要匹配的模式。也许(?:(

随机推荐