Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Из сокета может придти мусор?  (Прочитано 18713 раз)
0 Пользователей и 1 Гость смотрят эту тему.
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« : 08-06-2006 12:08 » 

Подскажите пожалустатакую вещь из сокета в принципе может придти не полная или поврежденная посылка?

Пишу простенький клиент сервер (сервер VC, тестовый клиент VB через компонент винсоск)  с котрым обмениваюсь пакетами заданной структуры, переодически у меня на стороне сервера в принятом пакете оказывается "мусор", которому в принципе неоткуда взяться. Он может взяться из канала или это стопроцентно что то не срастается у меня?   

Второй момент  если у меня открыт асинхронный сокет а читаю я так
lBuf  = recv(sChannel ,Buf  , MAXBUF, 0);
может ли дальше по ходу исполнения  в буфер упасть  еще один пакет(или дописаться еще часть) без вызова recv?
Записан

Да да нет нет все остальное от лукавого.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 08-06-2006 13:24 » 

Ошибка в твоем коде.
Пакеты "попадают" в буфер сокета, а recv() копирует из него данные в твой буфер.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #2 : 08-06-2006 15:37 » 

PSD, я борюсь с этим так: пишу "транспорт" ->

каждый байт передаётся в виде двух частей
-----------------------------------------------
0x10 - начало посылки (1 в старшей терраде)

0x0L - младшая тетрада 1-го байта (0 в старшей терраде - признак)
0x2H - старшая тетрада 1-го байта (2 в старшей терраде - признак)

... - второй байт данных
...

... - N - й байт данных
...

0x3R - конец посылки (3 в старшей терраде - признак , R - 4-битное CRC всех тетрад данных , например сумма)
-----------------------------------------------

например  09 AF 3E  -

10 00 29 0A 2F 03 2E 3R  // R == crc

-------
так я могу докачивать данные и чётко отделять одну посылку от другой , а кроме того - определять некорректно переданные данные в некоторых случаях
« Последнее редактирование: 08-06-2006 15:41 от Алексей1153 » Записан

sss
Специалист

ru
Offline Offline

« Ответ #3 : 09-06-2006 01:22 » 

При высокой загрузке системы (или высокой удаленности), может возникать склейка сетевых пакетов. То есть ты в цикле посылаешь два блока данных и ожидаешь что у тебя будет два выхода из recv. При этом в recv указываешь приемный буфер больший, чем ожидаемый блок данных (MAXBUF). В итоге за один recv может прийти несколько (необязательно целых!) блоков.
Это очень актуальная тема, если размеры структур переменные, а их целостность важна.
Я эмулирую данную ситуацию путем остановки ( в отладчике) сервера. Жду некоторое время (при этом клиенты не перестают отправлять данные), и запускаю сервер на выполнение. Затем смотрю, что возвращает recv. Борюсь с этим путем передачи перед блоком его размера, и цепочки накопительных буферов, имеющих состояние готов и не готов.
Записан

while (8==8)
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #4 : 09-06-2006 05:31 » 

Давайте, да бы не было путаницы, говорить, о чем речь!
sss, ты, как я понимаю, говоришь о датаграммных сокетах. Таких, как UDP.
UDP не гарантирует доставку и порядок приема пакетов. Лучше пользоваться TCP (байтовый двунаправленный поток) и реализуемый протокол обмена должен содержать сведения для определения границ и целостности записей.
Так же UDP-сокет не гарантирует, что одно чтение данных соотв. ровно одному пакету - пакет может быть считан из буфера за несколько раз или наоборот - несколько пакетов могут быть считаны из буфера за один раз. Надо понимать, что это чтение буфера, а не пакетов.
Смысл применять UDP если:
- протокол допускает потерю пакетов;
- доставка должна быть максимально быстрой, без накладных расходов вроде TCP-handshake и подтверждений о доставке;
- отправляющая программа не должна останавливаться на ожидание подтверждения приема.
Возможно, можно найти еще причины. Во всех остальных случаях лучше использовать TCP.
« Последнее редактирование: 09-06-2006 05:46 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
sss
Специалист

ru
Offline Offline

« Ответ #5 : 09-06-2006 07:00 » 

Я говорю об TCP. Порядок и целостность данных на уровне TCP (!) поддерживаются. TCP - потоковый протокол. Сколько данных успело накопиться в потоке - столько и будет возвращено, если только нет ограничения в размере буфера, указанного в вызове recv! Я потратил на выяснение этой подробности не один день...
Записан

while (8==8)
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #6 : 09-06-2006 07:15 » 

sss, ты видимо несколько неправильно понимаешь термины "Порядок и целостность данных"...
Гарантия порядка - это гарантия того, что данные отправленные в определенном порядке, будут приняты на удаленном конце в том же порядке.
Гарантия целостности (в TCP) - гарантия того, что данные не будут искажены. Если нет возможности доставить данные, то соединение будет разорвано.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
sss
Специалист

ru
Offline Offline

« Ответ #7 : 09-06-2006 08:03 » 

Вопрос звучал конкретно: из сокета может придти мусор?
Допустим ожидается:  sizeof( struct x) = 20;
Буфер:                      MAXBUF = 30;
В сетевом стеке         StackSize = 40; //Пришло два пакета
Возврат recv              30

Половина второго пакета - мусор (?!)

Записан

while (8==8)
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #8 : 09-06-2006 13:28 » 

sss, опять термины замучили? В TCP на уровне API сокета нет понятия пакетов - только байты.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
sss
Специалист

ru
Offline Offline

« Ответ #9 : 13-06-2006 00:37 » 

А по существу? Я могу обозвать пакетом все что угодно... Или не могу? Например, могу я обозвать это DNS - пакетом? Или не могу... DNS пакет - корректное название ?
Записан

while (8==8)
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #10 : 13-06-2006 05:20 » 

sss, дык, DNS, обычно, работает через UDP - датаграммы.

Тут где-то на форуме есть дискуссия на тему пакетов/байтов. Если не лень - поищи.
Принципы программирования попросту разные для датаграмм и байтовых потоков.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #11 : 13-06-2006 06:31 » 

sss,

Почему бы тебе не получать пакеты целиком, коль скоро ты знаешь их размеры?
Код:
#define MSGSIZE 20
int recv_message(char * outbuf) {
    int rest = MSGSIZE;
    char * ptr = outbuf;
    while (rest > 0) {
        int recv_res = recv(s, ptr, rest, 0);
        if (recv_res < 0) { /* обработка ошибки и выход */ return -1; }
        rest -= recv_res;
        ptr += recv_res;
    }
    /* на выходе из цикла буфер будет гарантированно заполнен */
    return 0;
}

В твоём примере половина второго "пакета" будет получена в следующем вызове recv.  В TCP неполученные данные хранятся в буфере приёмника.
« Последнее редактирование: 13-06-2006 06:52 от npak » Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #12 : 13-06-2006 06:45 » 

В TCP нельзя ожидать, что если вы отправили данные одним блоком (в одном вызове send), то и получены они будут одним вызовом recv.  Или что recv будет ждать, пока не заполнит весь буфер.

Во-первых, при отправке TCP буферизует данные и отсылает сегментами.  Размер сегментов, время ожидания при заполнении буфера и прочие параметры, влияющие на размер и время отправки пакета IP, в котором переносится сегмент TCP -- реализационно зависим.  Более того, на одной и той же реализации поведение TCP стека может различаться в зависимости от настроек ядра.  Поэтому я бы не стал рассчитывать на то, что если вы передали в send 20 байт, то ваши 20 байт будут переданы "одним пакетом".  Стек TCP вполне может их порезать, если ему будет так удобнее их отправлять.

Во-вторых, как скоро сегмент передаётся получателю?  Это тоже зависит от реализации.  На выходе тоже бывают буферы, поэтому конкретная реализация может подождать, пока прибудут ещё сегменты, и передать несколько сегментов за раз.  Или наоборот, часть сегмента передать сразу (сколько влезло в буфер), а остаток в другой раз.

Наиболее безопасно (чтобы потом не было очень больно при отладке) думать о TCP как о потоке, в котором границы между вашими сообщениями стираются напрочь.  Если вам нужно будет на стороне получателя восстанавливать сообщения из потока, то надо заранее позаботиться об этом.  Есть несколько способов:
* передавать сообщения фиксированного размера,
* передавать в начале сообщения его длину,
* вставлять в конце маркеры - специальные последовательности байт, которые не могут встретиться в теле сообщения

Соответственно, в первом случае читать из потока поблочно (см. пример функции recv_message). Во втором сначала читать размер сообщения, затем читать указанное количество байт. В третьем случае есть несколько стратегий (читать блоками, читать посимвольно) в зависимости от характера данных.
« Последнее редактирование: 13-06-2006 06:56 от npak » Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
sss
Специалист

ru
Offline Offline

« Ответ #13 : 13-06-2006 06:51 » 

npak! А если ты не знаешь сколько должен быть остаток? Мне не надо решений! У меня оно есть... Было дело, мой сервер долго работал в локальных сетях. Принцип его работы состоял в расшифровке коммандной строки (допустим SMS Улыбаюсь).
Допуcтим:

>ThreadAdd /name=1 /subsсriber="12234@pager.khakasnet.ru" /port=2222

и так далее. Т.е. смысл имеет только строка целиком.  А потом я его запустил через inet.   И понеслось... Решал  это несколькими путями. Отправлял:
1. Строка -> Конечный токен
2. Размер-> Строка
В любом случае, отработка приема сервером ДАЛЕКО НЕ ПРОСТОЕ ДЕЛО!

P.S.: Вопрос не я задавал...

P.P.S: Пока писал ответ, куда делся POST ?
Записан

while (8==8)
sss
Специалист

ru
Offline Offline

« Ответ #14 : 13-06-2006 06:53 » 

Обидно однако, PSD начал эту важную тему и не слышно его Жаль
Записан

while (8==8)
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #15 : 13-06-2006 07:11 » 

PSD работает,  читает вас и пытается придумать оптимальный алгоритм подс вою задачу,
По как обошелся постоянная
 длина пакета+ маркер начала(не уникальный) + маркер конца  (не уникальный)

При совпадении всех трех условий пакет считатеся принятым, если не совпадает  длинна значит пакет не полный, если  совпадает длинна но не совпадаетют маркеры значит  пакет дефектный...

На малой загрузке пока все работает, подключу еще пару приборов погоняю с большой загрузкой....


На данном этапе  отложил  проблему в "долгий" ящик, борюсь с сохраненим структуры транзакций в условиях не стабильных каналов связи с приборами.... 
   
Записан

Да да нет нет все остальное от лукавого.
sss
Специалист

ru
Offline Offline

« Ответ #16 : 13-06-2006 07:26 » 

Я уже молчу, если сервер многопоточный и не сериализирует прием... в общем, поверь на слово, посылай вначале размер - получай сам размер и жди остаток (положив в цепь буферов). Опять возникает recv, проверяй последний в цепочке, дополняй сколько нужно, создавай новый буфер, присоединяй в конец цепочки и пиши остатки в него. Создай поток, который будет проверять готовность цепочки (используй семафоры).
« Последнее редактирование: 13-06-2006 07:29 от sss » Записан

while (8==8)
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #17 : 13-06-2006 07:32 » new

В частности по причине проблем с разбором полученного потока для мультимедийных приложений был разработан новый транспортный протокол SCTP.

Он поддерживает многопоточность данных (в TCP на один сокет приходится один поток), разбиение на сообщения и гарантию времени задержки при передаче.

Правда, с реализациями у SCTP пока не густо.
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines