Асинхронная отправка и получение пользовательских пакетов данных с наддувом? - PullRequest
3 голосов
/ 14 апреля 2019

Я пытаюсь асинхронно отправлять и получать пользовательские пакеты данных с надстройкой, и у меня есть несколько вопросов, основанных на моей текущей реализации:

tcpclient.cpp

#include "tcpclient.h"
#include <boost/chrono.hpp>
#include "../utils/logger.h"

tcpclient::tcpclient(std::string host, int port) :
        _endpoint(boost::asio::ip::address::from_string(host), port), _socket(_ioservice) {

    logger::log_info("Initiating client ...");
}

void tcpclient::start() {
    connect();
    _ioservice.run();
}

void tcpclient::connect() {
    _socket.async_connect(_endpoint, std::bind(&tcpclient::connect_handler, this, std::placeholders::_1));
}

void tcpclient::receive() {
    boost::asio::async_read(_socket, boost::asio::buffer(data, HEADER_LEN), std::bind(&tcpclient::read_handler, this, std::placeholders::_1));
}

void tcpclient::connect_handler(const boost::system::error_code &error) {
    if (!error) {
        _status = CONNECTED;
        logger::log_info("Connected to " + get_remote_address_string());
        receive();
    } else {
        _status = NOT_CONNECTED;
        _socket.close();
        _timer.expires_from_now(boost::asio::chrono::seconds{2});
        _timer.async_wait(std::bind(&tcpclient::reconnect_handler, this, std::placeholders::_1));
        logger::log_info("Failed to connect");
    }
}

void tcpclient::reconnect_handler(const boost::system::error_code &error) {
    connect();
}

void tcpclient::read_handler(const boost::system::error_code& error, std::size_t bytes_transferred)
{
    logger::log_info("reading some data?");
}


std::string tcpclient::get_remote_address_string() {
    return _socket.remote_endpoint().address().to_string() + ":" + std::to_string(_socket.remote_endpoint().port());
}

tcpclient.h

#include <string>
#include <boost/asio.hpp>


enum ConnectionStatus{
    NOT_CONNECTED,
    CONNECTED
};


class tcpclient {

public:

    tcpclient(std::string host, int port);

    void start();

    void connect();

private:

    ConnectionStatus _status = NOT_CONNECTED;

    const int HEADER_LEN = 0x01;

    void receive();

    void connect_handler(const boost::system::error_code& error);

    void reconnect_handler(const boost::system::error_code &error);

    void read_handler(const boost::system::error_code& error);

    std::string get_remote_address_string();


    boost::asio::io_service _ioservice;
    boost::asio::ip::tcp::endpoint _endpoint;
    boost::asio::ip::tcp::socket _socket;
    boost::asio::steady_timer _timer{_ioservice, boost::asio::chrono::seconds{2}};

};

1) Имеет ли смысл добавить два отдельных обработчика для чтения и записи, один для заголовка, другой для тела?

2) Как я могу гарантировать, что могу отправлять и получать данные одновременно, не сталкиваясь с какими-либо проблемами? Требуется ли для этого несколько сокетов? Как обычно реализуется такая функциональность?

3) Как мне отправлять пользовательские структуры данных? Я хочу реализовать собственную структуру пакетов. Как бы я отправил такие объекты, есть ли у boost встроенный сериализатор? Как или пользовательские структуры данных отправлены и получены?

4) Что произойдет, если соединение разорвется во время отправки или получения данных? Обрабатываются ли такие исключения непосредственно в обработчиках приема / отправки путем проверки объекта errorcode на eof?

Базовый пример для этого очень поможет!

1 Ответ

3 голосов
/ 17 апреля 2019

1) Имеет ли смысл добавить два отдельных обработчика для чтения и записи, один для заголовка, другой для тела?

Да. Код другой, лучше всего использовать разные обработчики.

2) Как я могу гарантировать, что могу отправлять и получать данные одновременно, не сталкиваясь с какими-либо проблемами?

Асинхронные операции. Функции возвращаются немедленно, поэтому единственной задержкой является скорость сети.

3) Как мне отправлять пользовательские структуры данных?

boost::asio::buffer поддерживает отправку / получение необработанных байтов памяти. Когда этого недостаточно, asio имеет сериализацию:

4) Что произойдет, если соединение разорвется во время отправки или получения данных?

Все операции чтения и записи возвращают boost::system::error_code. Если возникает ошибка, сокет должен быть закрыт (и, если возможно, подключен снова). Какой-то базовый код:

void AfterReadingHeader(const boost::system::error_code & aError)
{
  if (aError)
  {
    // something went wrong 
    boost::system::error_code error;
    socket.shutdown(tcp::socket::shutdown_receive, error);
    socket.close(error);
  }

  ...
}
...