【问题标题】:results from Boost.Asio resolver differBoost.Asio 解析器的结果不同
【发布时间】:2012-06-14 23:09:21
【问题描述】:

我有一个罐头复制器每 5 秒在 localhost 上调用一次 boost::asio::ip::tcp::resolver::resolve()。它计算返回的端点数,并将该值与上一次迭代进行比较。

#include <boost/asio.hpp>

#include <iostream>

int main(int argc, char *argv[])
{
    if ( argc < 3 ) {
        std::cerr << argv[0] << " host port" << std::endl;
        exit( EXIT_FAILURE );
    }
    const char* host = argv[1];
    const char* service = argv[2];

    boost::asio::io_service io_service;
    boost::asio::ip::tcp::resolver resolver( io_service );

    size_t previous = 0;
    while ( true ) {
        boost::asio::ip::tcp::resolver::iterator i(
                resolver.resolve(
                    boost::asio::ip::tcp::resolver::query( host, service )
                    )
                );
        size_t count( 0 );
        while ( i != boost::asio::ip::tcp::resolver::iterator() ) {
            std::cout << i->endpoint() << std::endl;
            ++i;
            ++count;
        }

        std::cout << "got " << count << " addresses" << std::endl;
        if ( previous == 0 ) {
            previous = count;
        }
        assert( count == previous );

        sleep( 5 );
    }
}

示例会话

~> time ./addrinfo_asio localhost 80

...

127.0.0.1:80
got 1 addresses
[::1]:80
127.0.0.1:80
got 2 addresses
addrinfo_asio: addrinfo_asio.cc:35: int main(int, char**): Assertion `count == previous' failed.
Aborted (core dumped)

real    216m20.515s
user    0m0.181s
sys     0m0.193s
~> 

您可以看到它找到一个端点 (127.0.0.1:80) 大约 3.5 小时,然后找到两个端点(127.0.0.1:80 和 [::1]:80)。我想知道

  1. 为什么端点计数从一个变为两个?
  2. 可能是什么原因造成的?

同时解析 ipv4 和 ipv6 地址是有意的,我不想将查询限制为 ipv4。我意识到这种行为可能并非特定于 asio,我也有一个复制器直接调用 getaddrinfo,它表现出相同的行为。如果相关的话,我的平台是 ppc64 RHEL 6.2。我没有尝试在其他地方复制。

【问题讨论】:

  • ::1 地址是 IPv6 本地主机地址。也许操作系统需要很长时间才能意识到它启用了 IPv6?
  • 你运行的是什么操作系统?
  • @gda2004 看问题最后一句,ppc64 RHEL 6.2
  • @Sam Miller 很抱歉我错过了
  • @Sam Miller 你是在纯 IPv4 网络上吗?我只是在这里发表我的想法

标签: c++ sockets boost boost-asio getaddrinfo


【解决方案1】:

您只能将解析器限制为 IPv4:
ip::tcp::resolver::query(ip::tcp::v4(), 主机, 服务)

【讨论】:

  • AFAIU 的问题不是如何限制 getaddrinfo 返回的地址,而是为什么 IPv6 地址会在一段时间后出现。
  • 嗯,我的印象是主题启动者不知道他的解析器查询同时包含 ipv4 和 ipv6,所以他得到了 undesired ipv6 查询。另一方面,众所周知,ipv6 DNS 查询可能非常缓慢......
  • @IgorR。我知道::1 地址是ipv6-localhost,我已经编辑了我的问题以反映这一点。我不想将我的解析查询限制为 ipv4。
  • 非常感谢您。即使在连接到另一台本地服务器的本地计算机上进行测试时,我的连接时间(秒)也很慢。事实证明,如果我将搜索限制为 IPv4,它会很快。这是使用同步升压。我在非常特定的条件下运行我的代码,所以 ipv4 和同步对我来说并不重要。也许这会在未来对其他人有所帮助。
【解决方案2】:

如果您看一下 Chris Kohlhoff(asio 的作者)presentation on ipv6 and asio at boost con 2011,他会使用以下技巧。

他对端点列表进行了重新排序,因此 ipv4 端点在列表中排在首位,并带有注释“现实检查:IPv6 不太可能还可用”。

他的示例代码适用于 boost 1.47 中发布的 asio 版本,但由于他习惯随着 C++ 的发展不断更改 asio 实现,因此它不再适用于我正在使用的版本(asio 独立 1.18.0)。

无论如何,以下代码在 asio 1.18.0 中工作,它包含在 boost 1.74 中

auto resolverResults(mResolver.resolve(hostName, serviceName));
std::transform(resolverResults.begin(), resolverResults.end(), std::back_inserter(endpoints), [](const asio::ip::basic_resolver_entry<asio::ip::tcp>& entry) { return entry.endpoint(); });
std::stable_partition(endpoints.begin(), endpoints.end(), [](const asio::ip::tcp::endpoint& endpoint) { return endpoint.protocol() == asio::ip::tcp::v4(); });
auto endpointsWithIP4First = asio::ip::tcp::resolver::results_type::create(endpoints.begin(), endpoints.end(), hostName, serviceName);

【讨论】:

    【解决方案3】:

    好吧,我不是提升专家,但快速浏览告诉我它似乎默认使用AI_ADDRCONFIG(这很好,几乎应该总是使用它)。使用该标志,如果您至少配置了一个全局可路由 IPv6 地址,它只会返回 IPv6 地址。也许您的 IPv6 连接并不总是可用?

    【讨论】:

    • Windows 特定警告: AI_ADDRCONFIG 可能会导致查找本地主机失败。详情请见Boost ticket 8503
    猜你喜欢
    • 2016-03-01
    • 2021-05-11
    • 1970-01-01
    • 2016-01-18
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-26
    相关资源
    最近更新 更多