'boost aiso icmp socket: is having async_receive_from got called repeatedly sufficient?

when reading the official boost icmp aync example https://www.boost.org/doc/libs/1_78_0/doc/html/boost_asio/example/cpp03/icmp/ping.cpp:

 void start_receive()
    {
        // Discard any data already in the buffer.
        reply_buffer_.consume(reply_buffer_.size());

        // Wait for a reply. We prepare the buffer to receive up to 64KB.
        socket_.async_receive(reply_buffer_.prepare(65536),
                              boost::bind(&pinger::handle_receive, this, _2));
    }
 void handle_receive(std::size_t length)
    {
        // The actual number of bytes received is committed to the buffer so that we
        // can extract it using a std::istream object.
        reply_buffer_.commit(length);

        // Decode the reply packet.
        std::istream is(&reply_buffer_);
        ipv4_header ipv4_hdr;
        icmp_header icmp_hdr;
        is >> ipv4_hdr >> icmp_hdr;

        // We can receive all ICMP packets received by the host, so we need to
        // filter out only the echo replies that match the our identifier and
        // expected sequence number.
        if (is && icmp_hdr.type() == icmp_header::echo_reply && icmp_hdr.identifier() == get_identifier() && icmp_hdr.sequence_number() == sequence_number_)
        {
            // If this is the first reply, interrupt the five second timeout.
            if (num_replies_++ == 0)
                timer_.cancel();

            // Print out some information about the reply packet.
            chrono::steady_clock::time_point now = chrono::steady_clock::now();
            chrono::steady_clock::duration elapsed = now - time_sent_;
            std::cout << length - ipv4_hdr.header_length()
                      << " bytes from " << ipv4_hdr.source_address()
                      << ": icmp_seq=" << icmp_hdr.sequence_number()
                      << ", ttl=" << ipv4_hdr.time_to_live()
                      << ", time="
                      << chrono::duration_cast<chrono::milliseconds>(elapsed).count()
                      << std::endl;
        }
        start_receive();
    }

I've got some questions:

  • what if in handle_receive,I do some time-consuming work, say, acquire some lock just before the start_recieve got called again, will the demo example miss some icmp packets? I have this question because after some experiments, I found handle_receive got called only once instead of repeatedly after async handler registered, so you have to register the handler everytime handle_receive got fired

  • what can i do to avoid this situation?



Solution 1:[1]

what if in handle_receive,I do some time-consuming work, [...], will the demo example miss some icmp packets?

Yes. It will add latency. If the latency exceeds 5s, the request will be timed out.

say, acquire some lock just before the start_recieve got called again

That's a problem. The lock will not guard any async operations anyways. You have a flaw in your logic there. It's hard to tell without seeing the code or knowing what you'd use the lock for.

what can i do to avoid this situation?

Instead of locking, use a strand.

Instead of doing time-consuming work in a completion handler, do it on a different thread.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 sehe