Имеется клиент-серверное приложение. Сервер передает сообщения клиенту, число отправленных сообщений фиксируется. На клиентской стороне происходит асинхронный прием при помощи библиотеки 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 теряются данные и приложение не все получает, то скорее всего
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Есть батник принимающий видео трансляцию по RTP средствами gstreamerПытаюсь написать программу, которая делал бы тоже самое, что бы не было нужды...
Возникла задача, в которой надо обращаться с двумя соседними элементами множества setТакой вопрос: как это сделать? Гуглил, нигде не нашел...
Есть данная программа которая работает с принтером, проблема заключается в том что при попытке прочитать с ком порта ничего не происходит,...
Нужно перегрузить оператор "=" (присваивания для следующих типов данных)