boost asio async_read_some чтение только фрагментов данных

у меня есть сервер С++, который использует boost::asio для выполнения операций чтения/записи - запись сообщений работает нормально, но по какой-то причине я не могу заставить чтение работать

сообщение, которое я отправляю ему от клиента, представляет собой 15 16-битных беззнаковых шорт - мое тестовое сообщение таково:

1, 34, 7, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0

теперь на сервере я вижу такие вещи постоянно. чтение часто разбивается и/или умножается на 256

это один запуск, отправляющий его дважды

reading length = 8: [1 34 7 0 0 0 0 0]
reading length = 3: [1024 0 0]
reading length = 3: [0 0 0]
reading length = 8: [1 34 7 0 0 0 0 0]
reading length = 6: [1024 0 0 0 0 0]

это второй запуск, отправляющий его дважды

reading length = 8: [1 34 7 0 0 0 0 0]
reading length = 6: [1024 0 0 0 0 0]
reading length = 6: [1 34 7 0 0 0]
reading length = 1: [0] 
reading length = 0: []
reading length = 0: []
reading length = 2: [0 0]
reading length = 2: [0 0]
reading length = 1: [0]

это третий запуск, отправляющий его один раз (я не знаю, что здесь произошло)

reading length = 14: [256 8704 1792 0 0 0 0 0 1024 0 0 0 0 0]

Вот фактический код чтения сервера

void Session::start(void) {
  msg_interface->add_msg_listener(this);
  _socket.async_read_some(
    boost::asio::buffer(_read_data_buffer, READ_DATA_BUFFER_LENGTH),
    boost::bind(&Session::handle_read, this, boost::asio::placeholders::error,
      boost::asio::placeholders::bytes_transferred));
}

void Session::handle_read(const boost::system::error_code& error, std::size_t bytes_transferred) {
  if (error) {
    msg_interface->remove_msg_listener(this);
    delete this;
  } else {
    if (bytes_transferred != 0) {
      // print what we've received
      const int length = bytes_transferred / sizeof(uint16_t);
      std::cout << "reading length = " << length << ": [";
      for (int i = 0; i < length; i++) {
        const uint16_t data = ntohs(_read_data_buffer[i]);
        std::cout << data;
        if (i != length - 1) {
          std::cout << " ";
        }
      }
      std::cout << "]" << std::endl;
    }
    _socket.async_read_some(
      boost::asio::buffer(_read_data_buffer, READ_DATA_BUFFER_LENGTH),
      boost::bind(&Session::handle_read, this, boost::asio::placeholders::error,
        boost::asio::placeholders::bytes_transferred));
  }
}

переменные следующие

const int READ_DATA_BUFFER_LENGTH = 1024;

class AbstractSession {
protected:
  uint16_t _read_data_buffer[READ_DATA_BUFFER_LENGTH];
...

Есть одна вещь - я использую ту же службу ввода-вывода для записи сообщений при их получении (сервер общается со старым интерфейсом и отправляет полученные сообщения всем клиентам) и для чтения сообщений от клиентов. может ли это произойти при использовании одной и той же службы ввода-вывода для обоих?

Любые мысли о том, что я должен сделать, чтобы исправить это?


person sean christe    schedule 18.06.2012    source источник
comment
удалите это - в handle_read неправильно.   -  person stack user    schedule 03.07.2017


Ответы (1)


Ваш код делает то, что должен делать — считывает столько данных, сколько может. Вот почему функция async_read_some имя заканчивается на "некоторые" - он читает "некоторые" байты и не обещает сделать больше. В документации также говорится следующее:

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

Что похоже на ваш случай, если вы не переработаете свой приемник для обработки частичных чтений.

person Community    schedule 18.06.2012
comment
хорошо - я думаю, что мне интересно, мне нужно будет прочитать 3 входных сообщения разной длины - есть ли какая-то причина, по которой он читает только определенное количество, вместо того, чтобы читать полное сообщение? также - когда я использую async_read, он не считывает данные полностью (14 вместо 15), тогда сообщения становятся несинхронизированными (первое правильно прочитанное слово следующего сообщения добавляется к последнему сообщению - в следующем сообщении отсутствует первое слово), и я никогда не получаю правильного сообщения - я тоже тестирую на локальном хосте, поэтому не понимаю, почему он сбрасывает данные - person sean christe; 18.06.2012
comment
я также замечаю, что если я отправлю сообщение один раз в секунду от клиента, оно в конечном итоге синхронизируется и начнет правильно читать на сервере - я действительно сбит с толку, почему это происходит, а затем один раз из каждых 28 или 30, поэтому сообщения просто умножаются на 256. - person sean christe; 18.06.2012
comment
@seanchriste: TCP/IP, и особенно неблокирующее чтение/запись, выходит за рамки комментариев. Единственное, что я могу посоветовать, это найти хорошую книгу об этом. Вы не должны иметь возможность отправлять или получать полное сообщение, это потоковый протокол... - person ; 18.06.2012
comment
async_read в конечном итоге исправил это - я все еще не понимаю, почему использование async_read_some будет случайным образом умножать данные, которые он читает (похоже, что он сдвигал биты где-то вдоль строки) - но асинхронное чтение в конечном итоге решило эту проблему - я не видел любые проблемы с заказом, спасибо - person sean christe; 18.06.2012
comment
Без проблем. Async read some ничего не умножает. Он получает из стека ОС TCP/IP столько данных, сколько доступно для процесса. Количество байтов зависит от размера MTU, от того, как другая часть на самом деле отправляет данные (т. е. nagle включен или отключен) и т. д. В любом случае не думайте об этих числах как о магических числах — ничего не предполагайте. Что вы видите, то и получаете. Что делает async_read, так это просто получает эти фрагменты данных до тех пор, пока у него не будет достаточно байтов, а затем передает эти данные вам одним фрагментом. Так что под капотом он не делает ничего технически полезного. Просто упрощает вашу жизнь. - person ; 18.06.2012