Модераторы: feodorv
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> чтение дефрагментированных пакетов через сокет 
:(
    Опции темы
Cyr
Дата 10.2.2015, 14:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 48
Регистрация: 20.3.2006

Репутация: нет
Всего: нет



открываем сокет:
s=socket(AF_INET, SOCK_STREAM, 0)
читаем в бесконечном цикле из сокета:
nbytes=recv(s, buf, sizeof(buf), 0);
правильный пакет будет иметь формат: 0, [количество байтов], [сами байты...].
проблемма в том, что пакеты могут рваться в влюбом месте. и продолжаться в следующем пакете.
помогите правильно собрать пакет из фрагментов.
PM MAIL   Вверх
Cyr
Дата 10.2.2015, 16:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 48
Регистрация: 20.3.2006

Репутация: нет
Всего: нет



Код

nbytes=recv(s, buf, sizeof(buf), 0);
    if (nbytes == vbuf[1]+2) { // считался весь пакет
        memmove(buf, vbuf, nbytes);
    } else { // значит фрагмент
        printf("fragment 1:%d\n", nbytes);    
        memmove(buf, vbuf, nbytes);
        nbytes2=recv(s, vbuf, sizeof(buf), 0);
        printf("fragment 2:%d\n", nbytes2);    
        memmove(buf+nbytes, vbuf, nbytes2);
        nbytes = nbytes + nbytes2;
    }
    dump(buf, nbytes);

PM MAIL   Вверх
feodorv
Дата 10.2.2015, 17:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 10
Всего: 45



Цитата(Cyr @  10.2.2015,  16:10 Найти цитируемый пост)
       memmove(buf, vbuf, nbytes);

Здесь из vbuf копируются данные в buf (а не наоборот). Самих данных может накопиться много, что гарантирует выход за пределы массива. И второе чтение из сокета может не заполнить пакет до конца. Отсутствует обработка ошибок.


Само попакетное чтение из сокета можно организовать так:
Код

int getData( int s, char *buf)
{
  int nbytes, total = 0, length;

  while( total < 2 )
  {
    nbytes = recv( s, buf, 2, 0);
    if( nbytes == 0 ) return 0; // соединение закрыто удаленно
    if( nbytes < 0 ) return -1; // ошибка чтения из сокета
    total += nbytes;
  }

  if( buf[0] != 0 ) return -2; // испорченный пакет
  if( buf[1] == 0 ) return 2; // прочли 2 байта - пустой пакет
  length = ((unsigned char *) buf)[1] + 2;

  while( total < length )
  {
    nbytes = recv( s, &buf[total], length - total, 0);
    if( nbytes == 0 ) return 0; // соединение закрыто удаленно
    if( nbytes < 0 ) return -1; // ошибка чтения из сокета
    total += nbytes;
  }

  return total;
}


При этом buf должен быть размером не менее 255+2 байт (чтобы гарантировано влез любой пакет).

Это сообщение отредактировал(а) feodorv - 10.2.2015, 17:06


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Cyr
Дата 11.2.2015, 10:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 48
Регистрация: 20.3.2006

Репутация: нет
Всего: нет



feodorv,
Спасибо большое. 
vbuf - это временный буфер. Поэтому всё правильно.
Размер пакета не может превышать 2+240 байт. Это ограничение АТС, которая шлёт пакеты (прописано в её документации). И на практике пакет никогда не рвался более чем на 2 части.
Поэтому я и сделал так в своём примере.
Вопросик по этим проверкам: 
Код

if( buf[0] != 0 ) return -2; // испорченный пакет
  if( buf[1] == 0 ) return 2; // прочли 2 байта - пустой пакет

В TCP потоке могут быть испорченные пакеты?
И можно ли процедурку сделать только в один цикл, а не в 2 ?

Это сообщение отредактировал(а) Cyr - 11.2.2015, 11:13
PM MAIL   Вверх
feodorv
Дата 11.2.2015, 19:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 10
Всего: 45



Цитата(Cyr @  11.2.2015,  10:33 Найти цитируемый пост)
И на практике пакет никогда не рвался более чем на 2 части.

Практика - вещь тонкая, а где тонко, там и рвется. 100%ю гарантию от большего числа разрывов она не даст, а переписать 2 последовательных чтения из сокета в один компактный цикл (который вдобавок читает из сокета попакетно, без лишних байт) - дело несложное)))


Цитата(Cyr @  11.2.2015,  10:33 Найти цитируемый пост)
Размер пакета не может превышать 2+240 байт.

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


Цитата(Cyr @  11.2.2015,  10:33 Найти цитируемый пост)
В TCP потоке могут быть испорченные пакеты?

Бывает всякое. Но в данном случае скорее стоит защита от программных ошибок (как со стороны устройства, так и с нашей стороны). Например, мы можем ошибочно считать из сокета лишнее или наоборот. Согласно протоколу (прикладного уровня) первый байт в пакете должен быть нулем, так что нам стоит это проверить? А если не ноль, то протокол каким-то образом заблудился, нужно переустанавливать соединение с устройством.


Цитата(Cyr @  11.2.2015,  10:33 Найти цитируемый пост)
И можно ли процедурку сделать только в один цикл, а не в 2 ?

А это принципиально? Первый цикл считывает 2 байта из сокета, цикл нужен, если внезапно доступен только один байт, а второго нужно ждать. В общем, можно первый цикл заменить на 2 последовательных чтения по одному байту с проверкой ошибок при каждом чтении. Сами циклы в коде сделаны однотипно, для лучшего понимания)))




--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Cyr
Дата 12.2.2015, 09:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 48
Регистрация: 20.3.2006

Репутация: нет
Всего: нет



Цитата(feodorv @  11.2.2015,  20:03 Найти цитируемый пост)
 Первый цикл считывает 2 байта из сокета, цикл нужен, если внезапно доступен только один байт, а второго нужно ждать

У меня из вашей подпрограммы иногда происходит выход с кодом меньше 0.
Подозрение на то, что nbytes = recv( s, buf, 2, 0) читает только один байт, и выдаёт -1.
Сейчас проверяю.


Это сообщение отредактировал(а) Cyr - 12.2.2015, 09:30
PM MAIL   Вверх
feodorv
Дата 12.2.2015, 18:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 10
Всего: 45



Цитата(Cyr @  12.2.2015,  09:24 Найти цитируемый пост)
выход с кодом меньше 0

С каким точно?))) Не минус ли 2? А какой errno?


Цитата(Cyr @  12.2.2015,  09:24 Найти цитируемый пост)
Подозрение на то, что nbytes = recv( s, buf, 2, 0) читает только один байт, и выдаёт -1.

Эх, а там есть ошибка, должно быть:
Код

nbytes = recv( s, &buf[total], 2-total, 0);


Это сообщение отредактировал(а) feodorv - 12.2.2015, 18:39


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Cyr
Дата 13.2.2015, 09:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 48
Регистрация: 20.3.2006

Репутация: нет
Всего: нет



Ну вот. Спасибо.

Это сообщение отредактировал(а) Cyr - 13.2.2015, 10:47
PM MAIL   Вверх
Google
  Дата 23.5.2019, 16:19 (ссылка)  





  Вверх
  
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.1759 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.