2016-05-03 6 views
3

Ich habe das Beispiel http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/example/icmp/ping.cpp dahingehend geändert, wie man einen Host periodisch anpingt, um mehrere Hosts gleichzeitig anpingen zu lassen. Zuerst werden Anfragen für alle Hosts erstellt und an einen Socket gesendet. Dann werden in der zweiten Phase alle Antworten gesammelt, bis der Timer abläuft.Ein halbgleichzeitiger ICMP-Ping mit Boost.Asio unter Windows

Das modifizierte Beispiel 3 Clients:

// 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; 
} 

Die erste Iteration (0) jedes Mal, wie erwartet funktioniert, obwohl das erste Paket empfangen immer Null Länge hat. In allen folgenden Iterationen werden die Antworten von einem oder mehreren Clients jedoch nicht zugestellt, sondern eine Antwort von einem anderen Client wird stattdessen mehrmals geliefert. Mit Wireshark kann ich sehen, dass alle Hosts im Beispiel sehr schnell genau eine Antwort auf die Anfrage senden.

Dies ist eines der erzeugten Ausgänge:

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

Ist das eine korrekte Verwendung und das Verhalten von Boost.Asio?

Danke

Antwort

1

Scheint gut. Es scheint für mich zu funktionieren.

Hinweise:

  • streambuf mit scheinen allzu hier kompliziert - ich frage mich, ob die Wiederverwendung der streambuf wiederholte Feststellungen des gleichen Inhalts führt

  • das Zeug, wenn man von dem verwirrt werden kann Die Pooladressen werden an eine lokale NIC-Adresse aufgelöst (da Sie Ihre eigenen ICMP-Pakete erhalten)

  • Sie keine Adresse über die erste Übereinstimmung hinaus lösen, und überprüfen Sie das nicht Auflösung funktionierte überhaupt nicht; Außerdem können Sie jedes Mal beheben (dies könnte konstruktionsbedingt sein, könnte aber auch ein Fehler sein. DNS-Anfragen können auch Ihre Beobachtungen beeinträchtigen (besonders wenn Sie einen lokalen DNS-Cache/Gateway haben).

    Verwenden Sie boost::asio::async_resolve und wobei es vielleicht der Schleife aus, so dass es mit Timings nicht beeinträchtigt

Hier ist eine vereinfachte Version.

// 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(); 
    } 
} 

Drucke, zB

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