UDP сервер от boost не работает на многопоточности, но работает только в основном потоке - PullRequest
0 голосов
/ 11 июня 2019

Я получил асинхронный сервер 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();
    };
};

цель - вызвать сервер :: Запуск в фоновом режиме.

1 Ответ

0 голосов
/ 11 июня 2019

Прежде всего, у вас есть неопределенное поведение в start_send.

async_send_to немедленно возвращается, поэтому msg как локальная переменная уничтожается, когда возвращается start_send.Когда вы вызываете async_send_to, вы должны убедиться, что msg не уничтожен до завершения асинхронной операции.Что описано в документации -

Хотя объект буферов может быть скопирован по мере необходимости, владелец нижележащих блоков памяти сохраняется вызывающей стороной, , которая должна гарантирует, что они остаются действительными до тех пор, пока обработчик не будет вызван .

Вы можете разрешить это многими способами, проще всего использовать строку как элементы данных (как буфер для отправки данных):

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 content, то в [2] счетчик ссылок на строки shared_ptr увеличивается при вызове bind, поэтому время жизни строки увеличивается и уничтожается после вызова обработчика.


Относительно вашего неработающая на основе ниток.Вы не показали код, где вызывается Launch, но, возможно, вы просто не присоединяетесь к этой теме?

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

или, возможно, ваш код не работает UB в start_send.

...