Отправка и получение данных protobuf через Socket через boost asio - PullRequest
0 голосов
/ 27 мая 2019

Я хочу отправить данные Protobuf со своего сервера на мой клиент благодаря сокету TCP.

Я проверил мой клиент и мой сервер, и соединение TCP работает.

Поэтому я пытаюсь сериализовать свои данные и отправить их с помощью потокового буфера.

На моем сервере:

void SendData(protobufType data){
        std::ostream ostream(&this->m_streambuf);
        data.SerializeToOstream(&ostream);

        std::cout<<"Send data"<< std::endl;
        boost::asio::write(this->m_socket, this->m_streambuf);
}

В моем клиенте:

boost::asio::streambuf response;
boost::asio::read(socket, response);
std::cout<<"Data received"<< std::endl;

Я запускаю 3 раза мою функцию отправки (я думаю, мои швы данных должны быть отправлены), но швы myclient никогда не получают данные ...

1 Ответ

0 голосов
/ 27 мая 2019

Ваш клиент висит на этой линии

boost::asio::read(socket, response);

потому что выше то же самое, что и

boost::asio::read(socket, response, boost::asio::tranfer_all());

что описано в документации .

Вы используете read перегрузку, которая принимает условие завершения. Существует три вида этих функторов: transfer_all_t, transfer_exactly_t и transfer_at_least_t. Каждый из них имеет operator()(), который возвращает 0, если операция чтения завершена - см. Ссылку .

Код для transfer_all_t::opeator()():

  template <typename Error>
  std::size_t operator()(const Error& err, std::size_t)
  {
    return !!err ? 0 : default_max_transfer_size;
  }

, поэтому 0 возвращается только в случае возникновения ошибки.

transfer_at_least_t::operator()() - это:

  template <typename Error>
  std::size_t operator()(const Error& err, std::size_t bytes_transferred)
  {
    return (!!err || bytes_transferred >= minimum_)
      ? 0 : default_max_transfer_size;
  }

Как вы можете видеть, 0 возвращается, если произошла ошибка или было передано не менее minimum_ байт.

Если вы знаете, что read с transfer_all заканчивается при возникновении ошибки, вы можете создать эту ошибку, чтобы увидеть прочитанные данные. Вы можете отключить сокет (для отправки) на стороне сервера или просто закрыть этот сокет. Затем вы можете изменить read call, чтобы получить error_code, и вы должны увидеть Конец файла как ошибку:

boost::system::error_code ec;
boost::asio::read(socket,response,ec);
if (ec)
{
   cout << ec.message() << endl; // End of file
   // if ec is End of file you can see what data was read into streambuf
}

Вы отправляете сериализованный объект, чтобы вы знали размер этого объекта, почему бы не использовать подход, при котором вы отправляете размер объекта (например, 4 байта), тогда после этого заголовка содержимое объекта отправляется позже.

На стороне клиента:

array<char,4> length;
boost::asio::read(socket,boost::asio::buffer(length));
int contentLen = /*conversion from length array into integer */
vector<char> content( contentLen );
boost::asio::read(socket,boost::asio::buffer(content));
...