【问题标题】:A semi-concurrent ICMP ping using Boost.Asio on Windows在 Windows 上使用 Boost.Asio 的半并发 ICMP ping
【发布时间】:2016-05-03 12:18:55
【问题描述】:

我已经修改了示例http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/example/icmp/ping.cpp 关于如何定期 ping 主机以同时 ping 多台主机。 首先,创建所有主机的请求并将其发送到套接字。然后在第二阶段收集所有响应,直到计时器到期。

3 个客户端的修改示例:

// Headers from ping example:
// http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/example/icmp/
#include "icmp_header.hpp"
#include "ipv4_header.hpp"

#include <boost/asio.hpp>
#include <iostream>

using boost::asio::ip::icmp;
using boost::asio::deadline_timer;
using boost::asio::io_service;
using boost::asio::streambuf;
using boost::system::error_code;
using std::cout;
using std::endl;
namespace posix_time = boost::posix_time;

static const std::string BODY = "ping";
static const auto PROCESS = GetCurrentProcessId();

static int gSequence;
static io_service gService;
static icmp::socket gSocket(gService, icmp::v4());
static deadline_timer gTimer(gService);
static streambuf gReply;
static icmp::endpoint gReceiver;

void StartReceive()
{
    gSocket.async_receive_from(gReply.prepare(65536), gReceiver,
        [&](const error_code& error, size_t length)
    {
        gReply.commit(length);

        ipv4_header ipv4Hdr;
        icmp_header icmpHdr;
        std::string body(BODY.size(), 0);

        std::istream is(&gReply);
        is >> ipv4Hdr >> icmpHdr;
        is.read(&body[0], BODY.size());

        auto ip = ipv4Hdr.source_address().to_string();
        auto rc = gReceiver.address().to_string();
        auto id = icmpHdr.identifier();
        auto process = PROCESS;
        auto sn = icmpHdr.sequence_number();
        auto type = icmpHdr.type();

        cout << "  Length              = " << length << endl;
        cout << "  Error               = " << error << endl;
        cout << "  IP checksum         = " << ipv4Hdr.header_checksum() << endl;
        cout << "  IP address          = " << ip << endl;
        cout << "  Receiver address    = " << rc << endl;
        cout << "  ICMP identification = " << id << endl;
        cout << "  ICMP type           = " << (int)type << endl;
        cout << "  Process             = " << process << endl;
        cout << "  Sequence            = " << sn << endl;

        if (is
            && icmpHdr.type() == icmp_header::echo_reply
            && icmpHdr.identifier() == PROCESS
            && icmpHdr.sequence_number() == gSequence
            && body == BODY)
        {
            cout << "    > " << ip << endl;
        }

        cout << endl;

        gReply.consume(length);

        StartReceive();
    });
}

int main()
{
    icmp::resolver resolver(gService);

    icmp_header echoRequest;
    echoRequest.type(icmp_header::echo_request);
    echoRequest.identifier(PROCESS);

    for (gSequence = 0; gSequence < 3; ++gSequence)
    {
        cout << "----------------------------------------------------------" << endl;
        cout << "Iteration = " << gSequence << endl;
        cout << "----------------------------------------------------------" << endl;

        echoRequest.sequence_number(gSequence);
        compute_checksum(echoRequest, BODY.begin(), BODY.end());

        streambuf request;
        std::ostream os(&request);
        os << echoRequest << BODY;

        gService.reset();

        StartReceive();

        std::vector<std::string> pool
        {
            "10.170.110.29",
            "10.170.97.39",
            "10.170.7.52"
        };

        for (const auto & ip : pool)
        {
            icmp::resolver::query query(icmp::v4(), ip, "");
            auto dest = *resolver.resolve(query);

            gSocket.send_to(request.data(), dest);
        }

        gTimer.expires_from_now(posix_time::millisec(2000));
        gTimer.async_wait([&](const error_code& error) { gService.stop(); });

        gService.run();
        gReply.commit(gReply.size());
        gReply.consume(gReply.size());
    }

    return 0;
}

第一次迭代 (0) 每次都按预期工作,尽管接收到的第一个数据包的长度始终为零。但是,在所有后续迭代中,来自一个或多个客户端的响应不会被传递,而是来自另一个客户端的响应被传递多次。使用 Wireshark,我可以看到示例中的所有主机都非常迅速地对请求发送了一个响应。

这是产生的输出之一:

----------------------------------------------------------
Iteration = 0
----------------------------------------------------------
  Length              = 0
  Error               = system:10022
  IP checksum         = 0
  IP address          = 0.0.0.0
  Receiver address    = 0.0.0.0
  ICMP identification = 0
  ICMP type           = 0
  Process             = 20464
  Sequence            = 0

  Length              = 32
  Error               = system:0
  IP checksum         = 595
  IP address          = 10.170.97.39
  Receiver address    = 10.170.97.39
  ICMP identification = 20464
  ICMP type           = 0
  Process             = 20464
  Sequence            = 0
    > 10.170.97.39

  Length              = 32
  Error               = system:0
  IP checksum         = 31034
  IP address          = 10.170.110.29
  Receiver address    = 10.170.110.29
  ICMP identification = 20464
  ICMP type           = 0
  Process             = 20464
  Sequence            = 0
    > 10.170.110.29

  Length              = 32
  Error               = system:0
  IP checksum         = 51432
  IP address          = 10.170.7.52
  Receiver address    = 10.170.7.52
  ICMP identification = 20464
  ICMP type           = 0
  Process             = 20464
  Sequence            = 0
    > 10.170.7.52

----------------------------------------------------------
Iteration = 1
----------------------------------------------------------
  Length              = 32
  Error               = system:0
  IP checksum         = 594
  IP address          = 10.170.97.39
  Receiver address    = 10.170.97.39
  ICMP identification = 20464
  ICMP type           = 0
  Process             = 20464
  Sequence            = 1
    > 10.170.97.39

  Length              = 32
  Error               = system:0
  IP checksum         = 51419
  IP address          = 10.170.7.52
  Receiver address    = 10.170.7.52
  ICMP identification = 20464
  ICMP type           = 0
  Process             = 20464
  Sequence            = 1
    > 10.170.7.52

  Length              = 32
  Error               = system:0
  IP checksum         = 51419
  IP address          = 10.170.7.52
  Receiver address    = 10.170.7.52
  ICMP identification = 20464
  ICMP type           = 0
  Process             = 20464
  Sequence            = 1
    > 10.170.7.52    

----------------------------------------------------------
Iteration = 2
----------------------------------------------------------
  Length              = 32
  Error               = system:0
  IP checksum         = 593
  IP address          = 10.170.97.39
  Receiver address    = 10.170.97.39
  ICMP identification = 20464
  ICMP type           = 0
  Process             = 20464
  Sequence            = 2
    > 10.170.97.39

  Length              = 32
  Error               = system:0
  IP checksum         = 51407
  IP address          = 10.170.7.52
  Receiver address    = 10.170.7.52
  ICMP identification = 20464
  ICMP type           = 0
  Process             = 20464
  Sequence            = 2
    > 10.170.7.52

  Length              = 32
  Error               = system:0
  IP checksum         = 51407
  IP address          = 10.170.7.52
  Receiver address    = 10.170.7.52
  ICMP identification = 20464
  ICMP type           = 0
  Process             = 20464
  Sequence            = 2
    > 10.170.7.52

这是 Boost.Asio 的正确用法和行为吗?

谢谢

【问题讨论】:

    标签: c++ boost boost-asio icmp


    【解决方案1】:

    看起来不错。它似乎对我有用。

    注意事项:

    • 在这里使用streambuf 似乎过于复杂——我想知道streambuf 的重用是否会导致重复发现相同的内容

    • 如果其中一个池地址解析为本地 NIC 地址(因为您将收到自己的 ICMP 数据包),这些内容可能会变得混乱

    • 除了第一个匹配项之外,您永远不会解析任何地址,并且根本不检查解析是否有效;此外,您每次都会解决(这可能是设计使然,但也可能是一个错误。DNS 请求也可能会干扰您的观察(尤其是如果您有本地 DNS 缓存/网关?)。

      考虑使用boost::asio::async_resolve 并可能将其从循环中取出,以免干扰计时。

    这是一个简化版:

    // Headers from ping example:
    // http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/example/icmp/
    #include "icmp_header.hpp"
    #include "ipv4_header.hpp"
    
    #include <sys/types.h>
    #include <unistd.h>
    #include <boost/asio.hpp>
    #include <iostream>
    #include <sstream>
    
    using boost::asio::ip::icmp;
    using boost::asio::deadline_timer;
    using boost::asio::io_service;
    using boost::asio::streambuf;
    using boost::system::error_code;
    using std::cout;
    using std::endl;
    namespace posix_time = boost::posix_time;
    
    static const std::string BODY = "ping";
    static const auto PROCESS = getpid();
    
    static int gSequence;
    static io_service gService;
    static icmp::socket gSocket(gService, icmp::v4());
    static char gReply[65536];
    static icmp::endpoint gReceiver;
    
    void StartReceive() {
        gSocket.async_receive_from(boost::asio::buffer(gReply), gReceiver, [&](const error_code &error, size_t length) {
    
            ipv4_header ipv4Hdr;
            icmp_header icmpHdr;
            std::string body(BODY.size(), 0);
    
            std::istringstream is(std::string(gReply, length));
            is >> ipv4Hdr >> icmpHdr;
            is.read(&body[0], BODY.size());
    
            auto ip      = ipv4Hdr.source_address().to_string();
            auto rc      = gReceiver.address().to_string();
            auto id      = icmpHdr.identifier();
            auto process = PROCESS;
            auto sn      = icmpHdr.sequence_number();
            auto type    = icmpHdr.type();
    
            cout << " Length="              << length <<
                    " Error="               << error <<
                    " IP checksum="         << ipv4Hdr.header_checksum() <<
                    " IP address="          << ip <<
                    " Receiver address="    << rc <<
                    " ICMP identification=" << id <<
                    " ICMP type="           << (int)type <<
                    " Process="             << process <<
                    " Sequence="            << sn << "\n";
    
            if (is && icmpHdr.type() == icmp_header::echo_reply && icmpHdr.identifier() == PROCESS &&
                icmpHdr.sequence_number() == gSequence && body == BODY) {
                cout << "    > " << ip << endl;
            }
    
            cout << endl;
    
            StartReceive();
        });
    }
    
    int main() {
        icmp::resolver resolver(gService);
    
        icmp_header echoRequest;
        echoRequest.type(icmp_header::echo_request);
        echoRequest.identifier(PROCESS);
    
        for (gSequence = 0; gSequence < 3; ++gSequence) {
            cout << "----------------------------------------------------------" << endl;
            cout << "Iteration=" << gSequence << endl;
            cout << "----------------------------------------------------------" << endl;
    
            echoRequest.sequence_number(gSequence);
            compute_checksum(echoRequest, BODY.begin(), BODY.end());
    
            streambuf request;
            std::ostream os(&request);
            os << echoRequest << BODY;
    
            gService.reset();
    
            StartReceive();
    
            for (std::string ip : { "www.msn.com", "www.google.com" }) {
                icmp::resolver::query query(icmp::v4(), ip, "");
                auto dest = *resolver.resolve(query);
    
                gSocket.send_to(request.data(), dest);
                std::cout << "Sent to " << dest.endpoint() << "\n";
            }
    
            deadline_timer gTimer(gService);
            gTimer.expires_from_now(posix_time::millisec(2000));
            gTimer.async_wait([&](error_code) { gService.stop(); });
    
            gService.run();
        }
    }
    

    打印,例如

    ----------------------------------------------------------
    Iteration=0
    ----------------------------------------------------------
    Sent to 204.79.197.203:0
    Sent to 216.58.212.164:0
     Length=32 Error=system:0 IP checksum=49241 IP address=204.79.197.203 Receiver address=204.79.197.203 ICMP identification=8041 ICMP type=0 Process=8041 Sequence=0
        > 204.79.197.203
    
     Length=32 Error=system:0 IP checksum=5449 IP address=216.58.212.164 Receiver address=216.58.212.164 ICMP identification=8041 ICMP type=0 Process=8041 Sequence=0
        > 216.58.212.164
    
    ----------------------------------------------------------
    Iteration=1
    ----------------------------------------------------------
    Sent to 204.79.197.203:0
    Sent to 216.58.212.164:0
     Length=32 Error=system:0 IP checksum=49240 IP address=204.79.197.203 Receiver address=204.79.197.203 ICMP identification=8041 ICMP type=0 Process=8041 Sequence=1
        > 204.79.197.203
    
     Length=32 Error=system:0 IP checksum=5449 IP address=216.58.212.164 Receiver address=216.58.212.164 ICMP identification=8041 ICMP type=0 Process=8041 Sequence=1
        > 216.58.212.164
    
    ----------------------------------------------------------
    Iteration=2
    ----------------------------------------------------------
    Sent to 204.79.197.203:0
    Sent to 216.58.212.164:0
     Length=32 Error=system:0 IP checksum=49239 IP address=204.79.197.203 Receiver address=204.79.197.203 ICMP identification=8041 ICMP type=0 Process=8041 Sequence=2
        > 204.79.197.203
    
     Length=32 Error=system:0 IP checksum=5449 IP address=216.58.212.164 Receiver address=216.58.212.164 ICMP identification=8041 ICMP type=0 Process=8041 Sequence=2
        > 216.58.212.164
    

    【讨论】:

      猜你喜欢
      • 2020-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-25
      相关资源
      最近更新 更多