"Склеивание" сообщений ТСР |
Здравствуйте, гость ( Вход | Регистрация )
"Склеивание" сообщений ТСР |
pwp2008 |
19.10.2015, 19:31
Сообщение
#1
|
Студент Группа: Участник Сообщений: 29 Регистрация: 19.12.2014 Пользователь №: 4299 Спасибо сказали: 0 раз(а) Репутация: 0 |
Подскажите пож-та, встречалось ли Вам отправленные друг за другом сообщения (клиентом) получать в сервере "склееном" виде, как если бы это было одно сообщение. В чем причина такой работы по протоколу TCP\IP ? Разрулить эту проблему удалось несколько искусственным способом, хотя здесь может подойти и передача длины сообщения и/или контрольный суммы. Видимо так склеены могут быть не 2, а даже больше последовательных сообщений.
|
|
|
ViGOur |
20.10.2015, 9:09
Сообщение
#2
|
Мастер Группа: Модератор Сообщений: 3296 Регистрация: 9.10.2007 Из: Москва Пользователь №: 4 Спасибо сказали: 231 раз(а) Репутация: 40 |
Это нормально. Пакет может прийти неполный или склеенный с другим, а то и с несколькими.
Для того, чтобы нормально разбирать пакеты обычно для их отправки используют свою структуру данных, что-то вроде: По желанию можно добавить CRCTCP буфер можно расценивать как файл, в который пишутся данные одним потоком, а из другого потока ты эти данные разбираешь. |
|
|
pwp2008 |
20.10.2015, 19:09
Сообщение
#3
|
Студент Группа: Участник Сообщений: 29 Регистрация: 19.12.2014 Пользователь №: 4299 Спасибо сказали: 0 раз(а) Репутация: 0 |
Это нормально. Пакет может прийти неполный или склеенный с другим, а то и с несколькими. ............................................. TCP буфер можно расценивать как файл, в который пишутся данные одним потоком, а из другого потока ты эти данные разбираешь. Ну да, из практики вроде оно так и есть. Но ведь все таки по каким то правилам входной поток то прерывается ? Опять же, там вроде 7 или 8 уровней в протоколе ТСР и над ними опять нужно свои уровни добавлять, тем более с контрольными суммами ? Как то не ice..... По моему здесь как то завязана gui-технология обработки, пока приложение не выйдет на ожидание событий-поток в ТСР не прерывается, стоит только это организовать - сообщения перестают склеиваться. Может вообще вынести запись в сокет в отдельный thread (надо бы попробовать). |
|
|
ViGOur |
20.10.2015, 21:03
Сообщение
#4
|
Мастер Группа: Модератор Сообщений: 3296 Регистрация: 9.10.2007 Из: Москва Пользователь №: 4 Спасибо сказали: 231 раз(а) Репутация: 40 |
Ты не понял.
TCP стеку все равно, что в него попадает видео, звук или сообщения, он как получил так и отдал, твоя забота уже правильно разобрать переданые тобой данные. За пример можно взять лог файл, если не сделать правильное форматирование, то логи будут не читабельны, то же самое и здесь. Есть 3 варианта того, какими ты можешь получить свои сообщения: 1. Не полное сообщение (в том случае, если ты забираешь данные быстрей, чем они приходит) 2. Полное сообщения (идеальное стечение обстоятельств) 3. Склеенное сообщение (в том случае, если ты забираешь медленней, чем они приходят и склееным может быть как часть следующего пакета, так и несколько пакетов...) Обычно, чтобы всегда были идеальные условия используют структуру приведенную мной выше, по следующей схеме: 1. При поступленни данных читаем первые 4 байта, и приводим их к int, чтобы получить размер буфера. 2. Читаются столько байт, сколько указанно в первых четырех байтах полученных в 1 пункте. 3. Что-то там делаем с полученными данными. 4. Переходим к 1 пункту. Или чтобы не писать свой протокол над TCP, отправлять сообщения одной длины, например 1024 байта... |
|
|
pwp2008 |
25.10.2015, 18:11
Сообщение
#5
|
Студент Группа: Участник Сообщений: 29 Регистрация: 19.12.2014 Пользователь №: 4299 Спасибо сказали: 0 раз(а) Репутация: 0 |
Наработка по "склеиванию" сообщений такова : Имеем 2 простых приложения : 1-Сервер 2-Клиент (хотя кто из них Сервер, кто Клиент -чисто условное деление). Сервер по кнопке на своем окне высылает клиенту сообщение по сети ТСР\IP. Соединение между ними было преварительно установлено : сервер ждал соединения, Клиент - соединился и ждет сообщений от сервера. После получения его выдает его в свое окно. Так вот, если сообщение сервера оформлено как одно: string parcel_x = "wwwwwwwwwwwwwwwwwwwwwwwwwwwww"; int numBytes = firstClientSocket->write(parcel_x.data(),parcel_x.length()); то Клиент его получает и показывает. Если же поставить 2 сообщения подряд : string parcel_x = "wwwwwwwwwwwwwwwwwwwwwwwwwwwww"; int numBytes = firstClientSocket->write(parcel_x.data(),parcel_x.length()); string parcel_z = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"; int numBytes = firstClientSocket->write(parcel_z.data(),parcel_z.length()); ...................................... то Клиент получает только одно, но "склеенное" из 2-х сообщение. Хотелось бы понять причины этого и по возможности "разделить" сообщения, чтобы они приходили на клиент в виде 2 сообщений. Проверено следующее : Если второе сообщение выполнить по слоту однократного таймера через ххх мсек, то тогда склейки на клиенте нет : string parcel_x = "wwwwwwwwwwwwwwwwwwwwwwwwwwwww"; int numBytes = firstClientSocket->write(parcel_x.data(),parcel_x.length()); int xxx = 50; // интервал для срабатывания QTimer::singleShot(xxx,this,SLOT(slotMessage_2())); .............................. void PRG::slotMessage_2() { string parcel_z = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"; int numBytes = firstClientSocket->write(parcel_z.data(),parcel_z.length()); } и каждое сообщений приходит отдельно. Причем , уже при xxx > 11 . Если xxx=1, то сообщения "склеиваются" и в таком исполнении. Явное указание в сервере типа соединения = Qt::DirectConnection в методе connect : bool QObject::connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoConnection ) [static] "склеивания" не убирает( похоже может на Клиенте нужно было так же сделать ? на Клиенте я не ставил, упустил) Тексты приложений не привожу - это просто пример из Qt по технологии Клиент-Сервер. |
|
|
Влад |
26.10.2015, 14:45
Сообщение
#6
|
Участник Группа: Участник Сообщений: 146 Регистрация: 20.3.2009 Из: Санкт-Петербург Пользователь №: 627 Спасибо сказали: 46 раз(а) Репутация: 8 |
......Клиент получает только одно, но "склеенное" из 2-х сообщение. Хотелось бы понять причины этого и по возможности "разделить" сообщения, чтобы они приходили на клиент в виде 2 сообщений. ...... и каждое сообщений приходит отдельно. Причем , уже при xxx > 11 . Если xxx=1, то сообщения "склеиваются" и в таком исполнении. Еще раз: протокол TCP ничего не "знает" ни о каких сообщениях. TCP просто передает поток байтов от передатчика (передающей стороны) к приемнику. Все. Как он будет "склеивать" или наоборот "разрезать" твои сообщения - никто не дает никаких гарантий. В зависимости от загрузки сети при одном и том же исходном коде и одних и тех же таймаутах может быть и "склеивание", и "разрезание" сообщений - по внутреннему усмотрению драйвера TCP. Поэтому подбирать какие-либо таймауты, слоты и прочее - бессмысленно. Правильный подход тебе описал коллега ViGOur. |
|
|
ViGOur |
26.10.2015, 17:17
Сообщение
#7
|
Мастер Группа: Модератор Сообщений: 3296 Регистрация: 9.10.2007 Из: Москва Пользователь №: 4 Спасибо сказали: 231 раз(а) Репутация: 40 |
pwp2008, вот ты упрямец! Перечитай заново, что я описал выше.
Таймауты тебе могут помочь в том случае, если сервер или клиент не заняты, но если один из них занят (I\O операции или по процессору) то всеравно будет склейка и тайм ауты не помогут. Это из серии я надеюсь всё будет в порядке, но в программировании это не допустимо, потому нужно создавать условия, чтобы всё было в порядке. |
|
|
pwp2008 |
26.10.2015, 19:49
Сообщение
#8
|
Студент Группа: Участник Сообщений: 29 Регистрация: 19.12.2014 Пользователь №: 4299 Спасибо сказали: 0 раз(а) Репутация: 0 |
pwp2008, вот ты упрямец! Перечитай заново, что я описал выше. Не упрямый, а просто - неграмотный. Стаж по диалогу в TCP у меня небольшой, может год- полтора, на 2х или 3х приложениях, просто я ни разу до текущего приложения не попадал с такие ситуации("склеивание\разрезание"). Это, конечно, не довод. Но от всей этой ситуации повеяло безнадежностью : Цитата(ViGOur) Обычно, чтобы всегда были идеальные условия используют структуру приведенную мной выше, по следующей схеме: 1. При поступленни данных читаем первые 4 байта, и приводим их к int, чтобы получить размер буфера. 2. Читаются столько байт, сколько указанно в первых четырех байтах полученных в 1 пункте. 3. Что-то там делаем с полученными данными. 4. Переходим к 1 пункту. Т.е. 4 байта уж точно не разрежутся ? Вообще, можно и 2-мя обойтись, надежней. Сколько ждать полного буфера, длина, которого была заявлена в заголовке, ведь можем и не дождаться? Надеюсь, что ТСР не переставит блоки, а будет все-таки давать их в порядке отправления. Контрольная сумма меня особенно радует. Что ж, видимо с этим придется жить... Спасибо за помощь. Есть такой протокол - МЭК 104. Похоже нужно от него брать ряд идей. |
|
|
ViGOur |
27.10.2015, 10:30
Сообщение
#9
|
Мастер Группа: Модератор Сообщений: 3296 Регистрация: 9.10.2007 Из: Москва Пользователь №: 4 Спасибо сказали: 231 раз(а) Репутация: 40 |
4 байта было сказано для примера, ты сам решай, какой длины будет у тебя поле длина пакета. К тому же жестко указывать размер нельзя, а только sizeof(int), так как под разными системами int разного размера.
4 байта могут так же прийти по частям, это маловероятно, но может быть, например при медленном соединении или при крайней загруженности системы или сети. Блоки не переставляются и контрольные суммы по идее не нужны, так как TCP протокол гарантирует доставку пакета Набросал на коленке пример реализации: Тебе только осталось дописать докачку...Как вариант, во избежании склеивания, можно сделать клиент серверный диалог с подтверждением, например: 1. Клиент отправляет пакет 2. Сервер получает пакет 3. Сервер отправляет подтверждение о получении пакета 4. Клиент получает подтверждени и идет к 1 пункту |
|
|
Влад |
27.10.2015, 10:33
Сообщение
#10
|
Участник Группа: Участник Сообщений: 146 Регистрация: 20.3.2009 Из: Санкт-Петербург Пользователь №: 627 Спасибо сказали: 46 раз(а) Репутация: 8 |
Т.е. 4 байта уж точно не разрежутся ? Вообще, можно и 2-мя обойтись, надежней. Сколько ждать полного буфера, длина, которого была заявлена в заголовке, ведь можем и не дождаться? Надеюсь, что ТСР не переставит блоки, а будет все-таки давать их в порядке отправления. Контрольная сумма меня особенно радует. Разрежутся или нет четыре байта длины - никто тебе не даст никаких гарантий. Да это и не имеет значения. Просто вычитывай из сокета, пока не наберутся в начале посылки эти четыре байта. А потом вычитывай столько байтов, сколько заявлено в заголовке. Либо они дойдут, либо ты получишь ошибку связи и должен на нее как-то отреагировать. Да, TCP не переставит блоки, в этом можно быть уверенным. |
|
|
Текстовая версия | Сейчас: 25.11.2024, 9:09 |