草庐IT

c - 如果 getaddrinfo 失败一次,它将永远失败(即使在网络准备就绪之后)

coder 2023-06-20 原文

我正在编写一个作为 systemd service 运行的 C 应用程序在启动时(发行版:Arch Linux)并且应该连接到服务器。因为应用程序是在启动时运行的,所以最终会发生网络连接尚未建立的情况。这自然会导致需要一个的第一个函数失败,在我的例子中是 getaddrinfo

所以我想我会写一个循环,重复调用 getaddrinfo 直到它在网络准备就绪后成功。不幸的是,我发现即使在建立连接后,getaddrinfo 仍会失败并显示 name or service not known

我可以通过主机名 ping 服务器,但 getaddrinfo 仍然无法执行此操作。如果我停止应用程序并再次运行它,一切正常。如果网络连接在第一次调用之前已经建立,getaddrinfo 也可以正常工作。

显然,如果 getaddrinfo 因网络未就绪而失败一次,它将永远失败。它似乎没有意识到现在存在的连接。使用已弃用的 gethostbyname 时,行为是相同的。

这种行为的原因是什么?有没有办法强制 getaddrinfo 刷新内部变量(如果存在)或类似的东西,这可以解释为什么函数仍然认为没有连接?为了检查网络是否准备就绪,我应该提前调用另一个函数吗?

我想避免等待一段时间的延迟,期待网络在之后连接。我也更愿意从我的应用程序中检查连接,而不是让 bash 脚本先检查它然后启动应用程序。

最佳答案

您可以通过编译以下测试程序并按照以下说明理解答案:

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    while (1)
    {
        struct addrinfo *res;
        int rc=getaddrinfo(argv[1], "http", NULL, &res);

        printf("getaddrinfo returned %d\n", rc);

        if (rc == 0)
            freeaddrinfo(res);

        sleep(1);
    }
}

在运行这个测试程序之前:

  1. 连接到网络。
  2. /etc/resolv.conf暂时重命名为/etc/resolv.conf.save
  3. 启动这个测试程序,使用一个好的主机名。
  4. 在测试程序启动并开始打印错误代码后不久,将 /etc/resolv.conf.save 重命名为 /etc/resolv.conf
  5. 观察测试程序仍然报告 DNS 解析失败。
  6. 不过,如果您按 CTRL-C 并重新启动它,测试程序现在将报告有效的 DNS 解析。

当您断开并重新连接网络时,您的网络堆栈会相应地重写和更新 /etc/resolv.conf。 C 库中的 DNS 解析器需要此配置文件。 C库第一次从/etc/resolv.conf中读取DNS配置,并缓存起来。它不会在每次查找时检查 /etc/resolv.conf 的内容是否已更改。

最后:

  1. 你的家庭作业是添加对 resolv.h 中定义的 res_init() 的调用到这个测试程序,阅读相应的手册页,看看会发生什么发生。这就是你的答案。

关于c - 如果 getaddrinfo 失败一次,它将永远失败(即使在网络准备就绪之后),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30360029/

有关c - 如果 getaddrinfo 失败一次,它将永远失败(即使在网络准备就绪之后)的更多相关文章

  1. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  2. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  3. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  4. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  5. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

    我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

  6. ruby - 即使失败也继续进行多主机测试 - 2

    我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r

  7. ruby-on-rails - 如果我将 ruby​​ 版本 2.5.1 与 rails 版本 2.3.18 一起使用会怎样? - 2

    如果我使用ruby​​版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby​​1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更

  8. ruby - 通过 RVM 安装 Ruby 1.9.2 永远行不通! - 2

    当我执行>rvminstall1.9.2时一切顺利。然后我做>rvmuse1.9.2也很顺利。但是当涉及到ruby​​-v时..sam@sjones:~$rvminstall1.9.2/home/sam/.rvm/rubies/ruby-1.9.2-p136,thismaytakeawhiledependingonyourcpu(s)...ruby-1.9.2-p136-#fetchingruby-1.9.2-p136-#downloadingruby-1.9.2-p136,thismaytakeawhiledependingonyourconnection...%Total%Rece

  9. 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

  10. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

随机推荐