Имеется клиент-серверное приложение. Сервер передает сообщения клиенту, число отправленных сообщений фиксируется. На клиентской стороне происходит асинхронный прием при помощи библиотеки boost::asio. Пока что все действие происходит на localhost. Код приведен ниже.
void Client::on_read(Client *c, const boost::system::error_code &error, size_t received) {
if ((boost::asio::error::eof == error) || (boost::asio::error::connection_reset == error)) {
c->connectState(CONNECT_DISCONNECTED);
string msg = "Соединение с "+ c->verbal() + " потеряно, попытка повторного подключения...\n";
cout <<msg;
BOOST_LOG_SEV(lg, info) << msg;
c->disconnect();
c->connect();
}
else{
c->processData(received);
Sleep(50);
c->sock()->async_read_some(buffer(c->buf(), MODES_CLIENT_BUF_SIZE), boost::bind(on_read, c, _1, _2));
}
}
Проблема заключается в том, что часть пакетов не принимается клиентом. Причем число принятых пакетов больше, если поставить задержку перед очередным async_read_some(...). В чем может заключаться ошибка? Платформа Windows 10, MSVC 2013.
В TCP соединениях никто не гарантирует, что если с одной стороны отправлять пакетами по 1500 байт, то с другой будет прилетать и читаться такими же. И если на localhost ещё как то оно работает, то уже через обычный роутер часто нет. TCP гарантирует, что все байты придут и будет правильный порядок (либо соединение оборвется). Если же в TCP пакете потерялся байт/байты по середине или исказились данные, то это хоть и возможно теоретически (а больших датацентрах даже вылавливали подобное), но не нужно на это тратить силы (если только это не реализация tcp стека на какой то неведомой железяке с Китая).
Что же делать? При чтении проверять, пришел ли целый пакет данных (или даже несколько). Если да - парсить. А хвост оставлять. При последующих чтениях данные добавлять к этому хвосту и снова проверять.
Вполне возможно, что в Ваших пакетах нет явных признаков деления. Тогда очень плохо. Нужно либо выдумывать эвристику, либо модифицировать протокол. Два самых простых способа - это либо указывать размер в начале каждого пакета (тогда будет понятно, сколько читать, а сам размер имеет фиксированный размер), либо применять байт(ы)-разделитель (в текстовых протоколах, типа IRC это перевод строки). В бусте для этого есть read_until, которому нужно передать "предикат", который будет проверять, что пакет готов.
P.S. если Вы в Linux/Windows/Macos/FreeBSD столкнулись с тем, что по tcp теряются данные и приложение не все получает, то скорее всего
Виртуальный выделенный сервер (VDS) становится отличным выбором
Есть батник принимающий видео трансляцию по RTP средствами gstreamerПытаюсь написать программу, которая делал бы тоже самое, что бы не было нужды...
Возникла задача, в которой надо обращаться с двумя соседними элементами множества setТакой вопрос: как это сделать? Гуглил, нигде не нашел...
Есть данная программа которая работает с принтером, проблема заключается в том что при попытке прочитать с ком порта ничего не происходит,...
Нужно перегрузить оператор "=" (присваивания для следующих типов данных)