【问题标题】:How can I add an async timer to a boost UDP server?如何将异步计时器添加到 boost UDP 服务器?
【发布时间】:2016-12-15 02:17:46
【问题描述】:

我在网上获得了这段代码,并一直在尝试为其添加一个计时器,以便它每隔一段时间读取一个数据包。我似乎无法弄清楚如何将回调函数传递给 boost::async_wait 命令,因为我收到了这个错误:

server1.cpp: In member function ‘void UDPClient::handle_receive(const boost::system::error_code&, size_t)’:
server1.cpp:51:66: error: invalid use of non-static member function ‘void UDPClient::time_to_receive(const boost::system::error_code&)’
                                  boost::asio::placeholders::error));
                                                                  ^
server1.cpp:33:6: note: declared here
 void UDPClient::time_to_receive(const boost::system::error_code& error)
      ^~~~~~~~~

UDPClient 类:

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/array.hpp>
#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>

using boost::asio::ip::udp;

class UDPClient
{
public:
    boost::asio::io_service io_service;
    udp::socket socket;
    udp::endpoint receiver_endpoint;
    boost::asio::deadline_timer timer;
    boost::array<char, 1024> recv_buffer;

    UDPClient();
    void time_to_receive(const boost::system::error_code& error);
    void do_receive();
    void handle_receive(const boost::system::error_code& error, size_t);
};

UDPClient::UDPClient()
    : io_service(),
      socket(io_service, {udp::v4(), 3643}),
      timer(io_service, boost::posix_time::seconds(2))
{
    do_receive();
    io_service.run();
}

void UDPClient::time_to_receive(const boost::system::error_code& error)
{
    do_receive();
}

void UDPClient::do_receive()
{
    socket.async_receive_from(boost::asio::buffer(recv_buffer), receiver_endpoint,
                               boost::bind(&UDPClient::handle_receive, this,
                               boost::asio::placeholders::error,
                               boost::asio::placeholders::bytes_transferred));
}

void UDPClient::handle_receive(const boost::system::error_code& error, size_t bytes_transferred)
{
    std::cout << "Received: '" << std::string(recv_buffer.begin(), recv_buffer.begin()+bytes_transferred) << "'\n";

    timer.async_wait(boost::bind(time_to_receive,
                                 boost::asio::placeholders::error));
}

int main()
{
    UDPClient updclient;
}

我试图用这段代码回答的一个问题是,如果我用一堆 UDP 数据包从客户端向服务器发送垃圾邮件,服务器会在 async_wait 期间忽略所有数据包吗?

另外,我的主要目标是将此代码放入我拥有的四轴飞行器代码中。它会按照编写该类的方式工作,并让它从地面站读取数据包以获取用户输入吗?

【问题讨论】:

    标签: c++ sockets asynchronous boost boost-asio


    【解决方案1】:

    您使用bind 与成员函数的方式是错误的。如下所示使用它:

    timer.async_wait(boost::bind(&UDPClient::time_to_receive, this,
                                 boost::asio::placeholders::error));
    

    至于为什么会这样,我建议你阅读 boost 文档。

    此外,我还修改了代码,使其像服务器一样实际运行而无需退出。为此,我做了以下 2 处更改:

    1. 在主函数中初始化io_service,并将其引用传递给类。
    2. 初始化io_service_work 对象。这是io_service 的常年工作来源。因此,io_service 永远不会从 run 函数返回,除非 work 对象被销毁。

    完整来源:

    #include <boost/asio.hpp>
    #include <boost/bind.hpp>
    #include <boost/array.hpp>
    #include <iostream>
    #include <boost/date_time/posix_time/posix_time.hpp>
    
    using boost::asio::ip::udp;
    
    class UDPClient
    {
    public:
        boost::asio::io_service& io_service;
        udp::socket socket;
        udp::endpoint receiver_endpoint;
        boost::asio::deadline_timer timer;
        boost::array<char, 1024> recv_buffer;
    
        UDPClient(boost::asio::io_service&);
        void time_to_receive(const boost::system::error_code& error);
        void do_receive();
        void handle_receive(const boost::system::error_code& error, size_t);
    };
    
    UDPClient::UDPClient(boost::asio::io_service& ios)
        : io_service(ios),
          socket(io_service, {udp::v4(), 3643}),
          timer(io_service, boost::posix_time::seconds(2))
    {
        do_receive();
    }
    
    void UDPClient::time_to_receive(const boost::system::error_code& error)
    {
        do_receive();
    }
    
    void UDPClient::do_receive()
    {
        socket.async_receive_from(boost::asio::buffer(recv_buffer), receiver_endpoint,
                                   boost::bind(&UDPClient::handle_receive, this,
                                   boost::asio::placeholders::error,
                                   boost::asio::placeholders::bytes_transferred));
    }
    
    void UDPClient::handle_receive(const boost::system::error_code& error, size_t bytes_transferred)
    {
        std::cout << "Received: '" << std::string(recv_buffer.begin(), recv_buffer.begin()+bytes_transferred) << "'\n";
        timer.expires_from_now(boost::posix_time::seconds(2));
        timer.async_wait(boost::bind(&UDPClient::time_to_receive, this,
                                     boost::asio::placeholders::error));
    }
    
    int main()
    {
      boost::asio::io_service ios;
      boost::asio::io_service::work wrk(ios);
      UDPClient updclient(ios);
      ios.run();
    }
    

    注意:虽然它是一个服务器,但类名是Client。我忽略了:)

    【讨论】:

    • 哇,感谢您的来信。我什至没有意识到哈哈。至于更新,我实际上可以编译所以谢谢。但是,我遇到了一个新问题,即 async_wait 不会导致服务器等待 2 秒。我正在向服务器发送大量消息,它正在接收每条消息,并且在接收之间没有延迟。
    • 哦,好的,我明白了。 async_wait 在 2 秒后取消计时器,所以你必须调用 expires_from_now?
    • 现在它可以工作了,我测试了如果我从客户端向服务器发送垃圾邮件,使用 UDP 数据包会发生什么情况。即使我每 2 秒调用一次 async_receive_from,它仍然会收到每个数据包。所以它落后了很多。是否可以忽略 async_receive_from 调用之间的所有数据包?
    • 看来这解决了我之前的问题。 [stackoverflow.com/a/2770714/3884880]。他们建议像这样将 receive_buffer_size 选项设置为 0。 [boost.org/doc/libs/1_37_0/doc/html/boost_asio/reference/…。似乎按预期工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-27
    • 1970-01-01
    • 2014-06-18
    • 2015-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多