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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Сокеты Беркли, recv, recv гарантирует прием всего пакета? 
:(
    Опции темы
mad_lollipop
Дата 16.11.2008, 15:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Недавно начал  работать с сокетами, использую их в чистом виде, т.е. Сокеты Беркли+AF_INET, SOCK_STREAM, IPPROTO_TCP, потоковые, TCP. Возник вопрос, связанный с функцией recv. Если наш сокет не асинхронный, тогда при вызове этой функции мы ждем, пока во входном буфере сокета не появятся данные присланного пакета. При появлении данных в буфере мы можем обрабатывать полученное. Но вот что интересует больше всего: гарантируется ли полнота присланных данных, т.е. если нам послали 50 байт, то нам их столько и прийдет, или может возникнуть ситуация, когда нам эти 50 байт придут по частям, причем после получения первой части байтов наша программа получит возможность работы не дожидаясь получения следующих частей??? Возможно, все это реализуется на уровне TCP? Или как?


PM MAIL   Вверх
jonie
Дата 16.11.2008, 18:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

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



описанная ситуация вполне возможна, и зависит не только от настроек ОС, но и от устройства стека TCP\IP в системе...
а почему это вам должны давать сразу все присланные данные? может их там будет 20 мегабайт...


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
J0ker
Дата 16.11.2008, 19:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



для UDP пакет приходит целиком, если на recv запрошено меньше, то остаток теряется
для TCP возможна фрагментация пакетов (т.к. фактически пакетов нет - это потоковый протокол), при этом данный не теряются, даже когда в recv запрошено меньше имеющегося


--------------------
user posted image
PM MAIL   Вверх
MAKCim
Дата 16.11.2008, 22:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

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



Цитата(mad_lollipop @  16.11.2008,  15:13 Найти цитируемый пост)
или может возникнуть ситуация, когда нам эти 50 байт придут по частям, причем после получения первой части байтов наша программа получит возможность работы не дожидаясь получения следующих частей??? 

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


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
SVN74
Дата 17.11.2008, 00:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 740
Регистрация: 5.5.2008
Где: Комсомольск на Дн епре

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



Я был столкнулся с подобной проблемой при пересылке больших размеров данных (в МАССИВАХ), 
так как массив надо заполнить за один присест, пришлось смастерить свою функцию для полного заполнения массива:
Где:
 RecivedData - Массив данных
 SizeOfData - Размер массива
 SizeDataForSpeed - Можно устанавливать любую скорость но не  больше размера массива

///////////////////////////////////////////////////////////
Код

// Функция получения больших размеров данных через сеть
int  BigRecieve(SOCKET sck, char *RecivedData, int SizeOfData, int SizeDataForSpeed)
{
 int c,x=0; void *Ptr;
 try
 {
  char *TempAccp = new char[SizeDataForSpeed];
  do {
    c=recv(sck,&TempAccp[0],SizeDataForSpeed,0);
   if(c<0)
   {
   delete [] TempAccp;
   return -1;
   }
    Ptr = RecivedData+x;
    if(Ptr)
    x=x+c;
     if((c<0) || (SizeOfData < x) || (!Ptr))
    {
     delete [] TempAccp;
     return -1;
    }
     memcpy(Ptr,(void*)&TempAccp[0],c);
     } while(SizeOfData > x);
   delete [] TempAccp;
  }
  catch(...)
  {
   return -1;
  }
 return x;
}

Да... При ошибках будет возвращать -1

Это сообщение отредактировал(а) SVN74 - 17.11.2008, 00:21
PM MAIL WWW   Вверх
jonie
Дата 19.11.2008, 01:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

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



вспоминается тот незабываемый код, что когда-то писал наш офис в тайланде....
опишу пошагово (без обид, с юмором):
Цитата

Код

int  BigRecieve(SOCKET sck, char *RecivedData, int SizeOfData, int SizeDataForSpeed)
{
 int c,x=0; void *Ptr;
 try
 {
  char *TempAccp = new char[SizeDataForSpeed];  //завели буферок для скачивания (размер его скорость не даст 99%)

  do {
    c=recv(sck,&TempAccp[0],SizeDataForSpeed,0);  //начнем качать, неважно, что RecivedData может быть равен NULL -- хитроумно проверим дальше, а данные потеряем

   if(c<0)
   {
   delete [] TempAccp;
   return -1;
   }

//заведем магическую Х. Просто, нам лень делать было 
//"Ptr = RecivedData; Ptr += c;" - так могут все.
    Ptr = RecivedData+x;   

    if(Ptr)  //проверим на всякий случай (вдруг в первый раз RecivedData==NULL был?)
      x=x+c;

//
//и еще на всякий случай проверим Ptr (а вдруг RecivedData всеже был NULL?) 
//заодно проверим предоставленный размер буфера (про уже скаченные данные тупо забудем - они никому не нужны)
//на всякий случай перепроверим что C<0 (ведь "семь раз проверь - один отрежь")
     if((c<0) || (SizeOfData < x) || (!Ptr)) 
    {
     delete [] TempAccp;
     return -1;
    }
     memcpy(Ptr,(void*)&TempAccp[0],c); //пишем мы не зная что приводить к void* нет нужды...
     } while(SizeOfData > x);
   delete [] TempAccp;
  }
  catch(...)
  {
   return -1;  //а тут отчищать память от TempAccp не надо. "пусть всегда будет Солнце".
  }
 return x;

}




--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
SVN74
Дата 19.11.2008, 23:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 740
Регистрация: 5.5.2008
Где: Комсомольск на Дн епре

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



Цитата(jonie @  19.11.2008,  01:22 Найти цитируемый пост)
//начнем качать, неважно, что RecivedData может быть равен NULL -- хитроумно проверим дальше, а данные потеряем

Ну во первых чтобы использовать эту функцию буфер "RecivedData" заранее должен быть проверен и подготовлен
Цитата(jonie @  19.11.2008,  01:22 Найти цитируемый пост)
char *TempAccp = new char[SizeDataForSpeed];  //завели буферок для скачивания (размер его скорость не даст 99%)

Как ни странно на скорость влияет ...  smile 




Цитата(jonie @  19.11.2008,  01:22 Найти цитируемый пост)
    if(Ptr)  //проверим на всякий случай (вдруг в первый раз RecivedData==NULL был?)
      x=x+c;

//
//и еще на всякий случай проверим Ptr (а вдруг RecivedData всеже был NULL?) 
//заодно проверим предоставленный размер буфера (про уже скаченные данные тупо забудем - они никому не нужны)
//на всякий случай перепроверим что C<0 (ведь "семь раз проверь - один отрежь")
     if((c<0) || (SizeOfData < x) || (!Ptr)) 

Признаю... Лишнее... Можно вычеркнуть.  smile 




Цитата(jonie @  19.11.2008,  01:22 Найти цитируемый пост)
memcpy(Ptr,(void*)&TempAccp[0],c); //пишем мы не зная что приводить к void* нет нужды..

Здесь Ptr изначально void* - приводить не обязательно, иначе была бы ошибка, (проверено).


Цитата(jonie @  19.11.2008,  01:22 Найти цитируемый пост)
catch(...)
  {
   return -1;  //а тут отчищать память от TempAccp не надо. "пусть всегда будет Солнце".
  }


  smile  А тут я конечно “лоханулся”, спасибо добавлю очистку...
.....................................................................................................................
Несмотря на насмешки, этот код критических ошибок не имеет, конечно эго можно упростить вообще.
У меня эта функция скачивает сотнями Ггб в сети и ошибок не возникало, даже когда я ее принудительно садил на ошибки.
.....................................................................................................................
Что интересно, как только кто ни будь просит помощи в написании кода - помогать никто практически не хочет, тут я поддерживаю людей, которые помогают, тратя свое время...
Но вот (блеснуть своим умом) обсудить  чужой код , пускай не доскональный желающих довольно много, что интересно это чаще относится к людям у кого сообщений переваливает за 1000  - такой народ обычно ничего своего не выставляет...
БЕЗ ОБИД  smile 


PM MAIL WWW   Вверх
REZiaMIX
Дата 19.11.2008, 23:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(SVN74 @ 19.11.2008,  23:34)
Что интересно, как только кто ни будь просит помощи в написании кода - помогать никто практически не хочет, тут я поддерживаю людей, которые помогают, тратя свое время...
Но вот (блеснуть своим умом) обсудить  чужой код , пускай не доскональный желающих довольно много, что интересно это чаще относится к людям у кого сообщений переваливает за 1000  - такой народ обычно ничего своего не выставляет...
БЕЗ ОБИД  smile

Не в тему но:
Поддерживаю!


--------------------
user posted image
PM MAIL   Вверх
vinick
Дата 20.11.2008, 00:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(SVN74 @  19.11.2008,  23:34 Найти цитируемый пост)
Цитата(jonie @  19.11.2008,  01:22 Найти цитируемый пост)
Код

  catch(...)
  {
   return -1;  //а тут отчищать память от TempAccp не надо. "пусть всегда будет Солнце".
  }


  smile  А тут я конечно “лоханулся”, спасибо добавлю очистку...


У тебя исключения бросает только new. Так что никакой очистки не надо.
Код

        memcpy(Ptr,(void*)&TempAccp[0],c);
     } while(SizeOfData > x);

А теперь представь ситуацию SizeOfData=100, SizeDataForSpeed = 40 и у тебя recv 3 раза подряд прочитает по 40 байт. Потеря 20 байт и выход за границы массива в твоём приложении не критично ;)

Цитата(SVN74 @  19.11.2008,  23:34 Найти цитируемый пост)
Как ни странно на скорость влияет ...  smile 

Влияет, но очень опосредовано.
PM MAIL ICQ Jabber   Вверх
jonie
Дата 20.11.2008, 00:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

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



Цитата

Ну во первых чтобы использовать эту функцию буфер "RecivedData" заранее должен быть проверен и подготовлен
есть такой анти-паттерн : слепая вера зовется. использовать его надо с умом.

Цитата

У тебя исключения бросает только new. Так что никакой очистки не надо.
recv легко может дать exception (который, при опред махинациях с компилятором) будет ловиться catch-ем. ну и в общем-то не очень принято кушать exceptions все подряд. ну это так, к слову...

Цитата

Цитата

memcpy(Ptr,(void*)&TempAccp[0],c); //пишем мы не зная что приводить к void* нет нужды..
Здесь Ptr изначально void* - приводить не обязательно, иначе была бы ошибка, (проверено).
я про TempAccp говорил.

Добавлено через 3 минуты и 3 секунды
Цитата

Что интересно, как только кто ни будь просит помощи в написании кода - помогать никто практически не хочет, тут я поддерживаю людей, которые помогают, тратя свое время...
Но вот (блеснуть своим умом) обсудить  чужой код , пускай не доскональный желающих довольно много, что интересно это чаще относится к людям у кого сообщений переваливает за 1000  - такой народ обычно ничего своего не выставляет...
БЕЗ ОБИД   
не видел просьб написать код закачки данных.


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
SVN74
Дата 20.11.2008, 20:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 740
Регистрация: 5.5.2008
Где: Комсомольск на Дн епре

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



С учетом выше сказанных замечаний упростил свою функцию.
Работает также без проблем. 
Какие замечания будут?
Код

int BigRecieve(SOCKET sck, char *RecivedData, int SizeOfData)
{
 int X=0,rc;
     while(X<SizeOfData)
     {
       rc=recv(sck,&RecivedData[0]+X,SizeOfData-X,0);
       if(rc<=0) return -1;
       X+=rc;
     }
 return X;
}

PM MAIL WWW   Вверх
J0ker
Дата 20.11.2008, 21:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



о
а теперь как мы отличим - сокет закрывают или у нас ошибка?  smile 


--------------------
user posted image
PM MAIL   Вверх
SVN74
Дата 20.11.2008, 21:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 740
Регистрация: 5.5.2008
Где: Комсомольск на Дн епре

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



Цитата(J0ker @  20.11.2008,  21:05 Найти цитируемый пост)
о
а теперь как мы отличим - сокет закрывают или у нас ошибка?    

Ну на практике идет поток (бесконечный) и эта функция получает определенный размер данных, если поток завершится раньше, то сработает ошибка на “ресиве” и возвращается -1.
Ну конечно передающий код не должен быть с перерывами, так как будет ожидание пока не дойдут все данные...


PM MAIL WWW   Вверх
J0ker
Дата 20.11.2008, 21:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



вы меня не поняли
как определить - сокет закрыли с той стороны или у нас чего-то сломалось?


--------------------
user posted image
PM MAIL   Вверх
SVN74
Дата 20.11.2008, 21:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 740
Регистрация: 5.5.2008
Где: Комсомольск на Дн епре

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



Цитата(J0ker @  20.11.2008,  21:49 Найти цитируемый пост)
вы меня не поняли
как определить - сокет закрыли с той стороны или у нас чего-то сломалось? 

По такой причине, может ожидать до ~ 30 сек и срабатывает ошибка, - (опробовано), если конечно разрыва вообще нет будет ждать вечно, ну я думаю это практически не реально, практически всегда сокет разрывается.


Это сообщение отредактировал(а) SVN74 - 20.11.2008, 21:57
PM MAIL WWW   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Сети | Следующая тема »


 




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


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

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