curl/websocketpp库,公网域名解析慢、超时

树莓派问题现象:

  1. 使用curl库,http访问公网域名,连接超时;
  2. 使用websocketpp库,ws访问公网域名,连接超时
  3. 使用命令行ping域名,也要15s以上

Android上问题现象:

  1. 使用curl库,http访问公网域名,正常;
  2. 使用websocketpp库,ws访问公网域名,连接超时
  3. 使用命令行ping域名,正常

相关异常打印:

con->get_ec().message()返回 Timer Expired
get_local_close_code 返回 1006

ws端分析过程:

libwebsocketpp库连接流程分析:

3rd/libwebsocketpp/0.8.2/include/websocketpp/roles/client_endpoint.hpp
transport_type::async_connect

3rd/libwebsocketpp/0.8.2/include/websocketpp/transport/asio/endpoint.hpp
void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb)
     m_resolver->async_resolve

3rd/libasio/1.18.1/include/asio/detail/resolver_service.hpp
 void async_resolve
     start_resolve_op(p.p)

3rd/libasio/1.18.1/include/asio/detail/resolve_query_op.hpp 
 static void do_complete
     socket_ops::background_getaddrinfo

3rd/libasio/1.18.1/include/asio/detail/impl/socket_ops.ipp
asio::error_code background_getaddrinfo
    socket_ops::getaddrinfo(host, service, hints, result, ec);
        asio::error_code getaddrinfo
            int error = ::getaddrinfo(host, service, &hints, result);
getaddrinfo是系统函数
树莓派上直接demo直接调用getaddrinfo解析ai.cvte.com也会超时
Android上直接调用getaddrinfo也会超时

原因是:getaddrinfo(host, service, &hints, result);的hints.ai_family=AF_UNSPEC
看介绍:

ai_family参数指定调用者期待返回的套接口地址结构的类型。
它的值包括三种:AF_INET,AF_INET6和AF_UNSPEC。如果指定AF_INET,那么函数九不能返回任何IPV6相关的地址信息;如果仅指定了AF_INET6,则就不能返回任何IPV4地址信息。AF_UNSPEC则意味着函数返回的是适用于指定主机名和服务名且适合任何协议族的地址。如果某个主机既有AAAA记录(IPV6)地址,同时又有A记录(IPV4)地址,那么AAAA记录将作为sockaddr_in6结构返回,而A记录则作为sockaddr_in结构返回

赋值位置:3rd\libasio\1.18.1\include\asio\ip\basic_resolver_query.hpp hints_.ai_family = ASIO_OS_DEF(AF_UNSPEC);
修改为 hints_.ai_family = ASIO_OS_DEF(AF_INET); 测试速度很快。

可是这个地方是asio库写死的,直接改这里不妥,以后更新库可能会被覆盖

3rd\libasio\1.18.1\include\asio\ip\basic_resolver_query.hpp
不仅有:
basic_resolver_query(const std::string& host, const std::string& service,
    resolver_query_base::flags resolve_flags = address_configured)
    (此处是写死 hints_.ai_family = ASIO_OS_DEF(AF_UNSPEC);)
还有:
basic_resolver_query(const protocol_type& protocol,
    const std::string& service,
    resolver_query_base::flags resolve_flags = passive | address_configured)
    (此处是用hints_.ai_family = protocol.family();)
所以要分析如何使其调用后者

3rd\libasio\1.18.1\include\asio\ip\basic_resolver.hpp
有:
    results_type resolve(ASIO_STRING_VIEW_PARAM host,ASIO_STRING_VIEW_PARAM service, resolver_base::flags resolve_flags)
    {
      basic_resolver_query<protocol_type> q(static_cast<std::string>(host),static_cast<std::string>(service), resolve_flags);
也有:
    results_type resolve(const protocol_type& protocol,ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service,resolver_base::flags resolve_flags)
    {
      basic_resolver_query<protocol_type> q(protocol, static_cast<std::string>(host),static_cast<std::string>(service), resolve_flags);

3rd\libwebsocketpp\0.8.2\include\websocketpp\transport\asio\endpoint.hpp
    tcp::resolver::query query(host,port); 
    此处调用了上面的 basic_resolver_query(const std::string& host
    改成:tcp::resolver::query query(tcp::v4(),host,port);就可以跑入basic_resolver_query(const protocol_type& protocol

树莓派上不仅ws会超时,http也会超时,所以curl库也要指明只解析ipv4
curl_easy_setopt(curl, CURLOPT_IPRESOLVE,CURL_IPRESOLVE_V4);

总结:

原因是,服务端没有配置ipv6域名,dns解析的时候同时解析ipv4和ipv6,阻塞等待结果超时。
修改方法是,网络库指明只解析ipv4地址

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值