使用Boost的半并发ICMP ping.Asio在Windows上

A semi-concurrent ICMP ping using Boost.Asio on Windows

本文关键字:Asio Windows ping ICMP Boost 并发 使用      更新时间:2023-10-16

我修改了这个例子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的正确用法和行为吗。阿西奥?

感谢

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

注:

  • 在这里,使用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