来自 boost 的 Udp 服务器不能在多线程上工作,但只能在主线程上工作

Udp server from boost not working on multithreading, but work only on the main thread

我有一个异步 udp 服务器 boost::asio 但问题是: 如果我在线程上启动它,服务器将无法工作 但是如果我在主线程上启动它(阻塞服务)它正在工作...

我试过用叉子来做,但 eiser 不行

class Server {
private:
    boost::asio::io_service _IO_service;
    boost::shared_ptr<boost::asio::ip::udp::socket> _My_socket;
    boost::asio::ip::udp::endpoint _His_endpoint;
    boost::array<char, 1000> _My_Buffer;

private:

    void Handle_send(const boost::system::error_code& error, size_t size, std::string msg) {
    //do stuff
   };

    void start_send(std::string msg) {
        _My_socket->async_send_to(boost::asio::buffer(msg), _His_endpoint,
            boost::bind(&Server::Handle_send, this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred, msg));
    };

    void Handle_receive(const boost::system::error_code& error, size_t size) {
    //do stuff
    };

    void start_receive(void) {
        _My_socket->async_receive_from(
            boost::asio::buffer(_My_Buffer), _His_endpoint,
            boost::bind(&Server::Handle_receive, this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred));
    }

public:
    Server(int port):
    _IO_service(),
    _My_socket(boost::make_shared<boost::asio::ip::udp::socket>(_IO_service, \
        boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port)))
    {
        start_receive();
    };

    void Launch() {
        _IO_service.run();
    };
};

objective是后台调用Server::Launch

首先你在 start_send.

中有未定义的行为

async_send_to returns 立即,所以 msg 作为局部变量在 start_send returns 时被销毁。当您调用 async_send_to 时,您必须确保 msg 在异步操作完成之前未被销毁。描述的内容 in documentation -

Although the buffers object may be copied as necessary, ownership of the underlying memory blocks is retained by the caller, which must guarantee that they remain valid until the handler is called.

可以通过多种方式解决,最简单的就是使用string作为数据成员(作为发送数据的缓冲区):

class Server {
    //..
    std::string _M_toSendBuffer;
    // 
    void start_send(std::string msg) {
        _M_toSend = msg; // store msg into buffer for sending
        _My_socket->async_send_to(boost::asio::buffer(_M_toSend), _His_endpoint,
            boost::bind(&Server::Handle_send, this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred, 
                _M_toSend));
    };

另一种解决方案是将msg包装成智能指针以延长其生命周期:

void Handle_send(const boost::system::error_code& error, size_t size, 
        boost::shared_ptr<std::string> msg) {
   //do stuff
};

void start_send(std::string msg) {
    boost::shared_ptr<std::string> msg2 = boost::make_shared<std::string>(msg); // [1]
    _My_socket->async_send_to(boost::asio::buffer(*msg2), _His_endpoint,
        boost::bind(&Server::Handle_send, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred, 
            msg2)); // [2]
};

在 [1] 行中我们创建 shared_ptr 获取 msg 内容,然后在 [2] 行中 shared_ptr 的引用计数器在调用 bind 时增加, 因此字符串的生命周期被延长,并在处理程序被调用后被销毁。


关于您的 not-working 基于线程的版本。您没有显示调用 Launch 的代码,但也许您只是不加入此线程?

Server s(3456);
boost::thread th(&Server::Launch,&s);
th.join(); // are you calling this line?

或者您的代码在 start_send.

中无法通过 UB 运行