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

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

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

« : 25-04-2008 12:13 » 

Здравствуйте. Решил обратится за помощью, потому как не очень представляю как реализовать поставленную мне задачу.
Программка должна быть сервером. К ней по сети (Ethernet) может подключится до 272 устройств.
Для сервера я могу реализовать сокет и он будет слушать.
Чтоб главное окошко не тормозить нужно обработку приема-получения данных запихивать в отдельный поток.
Т.к. неизвестно когда одно из 272 возможных клиентов захочет что-нибудь послать, а реагировать нужно как можно быстрее.
Так вот, каким образом мне реализовать чтоб возвращаемый по accept() сокет (который я и буду пользовать для связи) был в отдельном потоке. Какие потоку лучше передавать параметры?
Общение между главным и всеми остальными потоками планирую через сообщения сделать. Еще вопрос, можно ли запихнуть в параметры сообщения указатель на массив данных (те данные, что приняты сокетом).
И что будет если я запущу 272+1 потока? и как мне их потом различить?
в общем буду рад любой помощи Улыбаюсь
Заранее спасибо Улыбаюсь
« Последнее редактирование: 14-01-2009 05:04 от Алексей1153++ » Записан
McZim
Команда клуба

ru
Offline Offline
Пол: Мужской
Я странный


WWW
« Ответ #1 : 25-04-2008 12:20 » 

это под венду?
Записан

The CBO without stats is like a morning without coffee. (c) T.Kyte.
tom4ik85
Участник

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

« Ответ #2 : 25-04-2008 12:28 » 

Да
Записан
Вад
Модератор

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

« Ответ #3 : 25-04-2008 12:31 » 

Ну, ты можешь в одном потоке делать select на несколько сокетов, насколько я понимаю. Тогда 272 потока не понадобится...
Если же хочешь использовать сокет в отдельном потоке - создай класс по типу Receiver, который управляет потоком, и передавай туда свой accept-нутый сокет, а дальше получай/передавай из другого потока через сокет.
« Последнее редактирование: 25-04-2008 12:33 от Вад » Записан
tom4ik85
Участник

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

« Ответ #4 : 25-04-2008 12:51 » 

В смысле селект на несколько сокетов?
И как мне без такого кол-ва потоков оперативно реагировать на сообщения из сети?
А гда можно посмотреть что такое Reciever и как он выглядит, чтоб что-то похожее сделать?
Нельзя ли сделать что-то типа:
Сервер слушает. Приходит запрос с клиента. При этом я запускаю поток и передаю ему какую-то ифу для инициализации (HWND диалога, int номер сокета, указатель на сокет или его копию и т.д.).
Сокет, тот что после accept вернулся создавать внутри потока и работать там с ним.
Т.е. поток для обработки сокета одинаковый и я его запускаю н-ное кол-во раз?
Формат данных то устройств одинаковый, потому и хочу как-то универсализировать это дело.
Записан
McZim
Команда клуба

ru
Offline Offline
Пол: Мужской
Я странный


WWW
« Ответ #5 : 25-04-2008 12:57 » 

tom4ik85, может лучше почитать про концепцию потоковых серверов?
Записан

The CBO without stats is like a morning without coffee. (c) T.Kyte.
tom4ik85
Участник

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

« Ответ #6 : 25-04-2008 13:03 » 

А где почитать?
Буду благодарен за ссылки.
Записан
Вад
Модератор

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

« Ответ #7 : 25-04-2008 13:10 » 

tom4ik85, Receiver - это я его условно назвал, первое что в голову пришло - это когда сокет + поток оборачиваются в класс, в частном случае, получающий данные (более общий - приём-передача).

Как это случалось реализовывать:
Есть некий владелец слушающего сокета, он в своём потоке сидит себе и слушает. Как только дослушался до accept, стучит куда надо (хозяину), отдавая ему новый открытый сокет.
Хозяин конструирует в зависимости от потребностей обёртку для этого нового сокета, имеющую свой поток и там получающую/передающую данные (обёртка может обладать своей очередью для приёма-передачи, например, или отдавать полученные данные наружу через переданный ей интерфейс). Дальше с сокетом вся работа идёт через обёртку.

Не берусь судить, насколько хороша такая схема с точки зрения проектирования, но вполне себе реализуемая

Что до функции select, то читай тот же MSDN Ага Да и остальное про сокеты можешь почитать там же

Ещё, в случае потребности работы с отдельным потоком я обычно делаю так: есть класс, у него среди свойств есть поток (обёртка или хэндл). при создании потока для объекта туда передаётся указатель на сам объект. И дальше уже из функции потока вызывается нестатическая функция объекта. Главное - грамотно потоки завершать, чтобы до вызова деструктора (или во время него) поток был завершён, чтобы без эксцессов Улыбаюсь
« Последнее редактирование: 25-04-2008 13:18 от Вад » Записан
tom4ik85
Участник

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

« Ответ #8 : 25-04-2008 14:34 » 

Примерно так:
Код:
class CMySock : CAsyncSocket
{
public:
     CMySock(CAsyncSock* sock);
     ~CMySock();
     ...........
protected:
     CAsyncSocket m_socket;
     HANDLE hThread;
     ...........
}

DWORD WINAPI Thread(void* lParam)
{
     Param* m_param = (Param*)lParam;
     CWnd* pWnd = m_param->pWnd; // указатель на мое окошко, чтоб сообщения посылать
     CAsyncSocket* s = m_param->sock;
     s->Recieve(...);
     ...........
     pWnd->SendMessage(WM_MY);
     ...........
     return 0;
}

CMySock::CMySock(CAsyncSock* sock)
{
     if(hThread == NULL)
     {
          sock->Accept(m_socket);
          ...........
          hthread = CreateThread(NULL, 0, Thread, &MyParam, CREATE_SUSPENDED, NULL);
     }
}
у меня просто такой сумбур в голове Жаль
я только недавно начал изучать потоки, и что-то медленно движется Жаль
Только сильно не ругайте, если глупостей много.
Лучше скажите где неправильно - буду разбираться.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

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


« Ответ #9 : 25-04-2008 16:10 » 

tom4ik85, не нужны потоки -
один сокет пользуешь чисто как слушалку - когда клиент хочет подключиться, вызывается виртуальный метод OnAccept.
Слушающий сокет создаёт пару для подключаюзщегося сокета (через Accept) и забывает про них. Совсем Улыбаюсь
Если подключать клиент по какой то причине не захотелось,  надо вызвать Accept вхолостую - создать временный парный сокет, асептнуть и тут же убить. Иначе почему то удалённый сокет будет долбиться и долбиться

у клиентского сокета , когда его асептнули, будет вызван метод OnConnect

Ещё надо включить соответствующие события у сокетов - через AsyncSelect
Записан

lapulya
Молодой специалист

ru
Offline Offline

« Ответ #10 : 16-05-2008 04:34 » 

Не уверен, что подобный подход (я имеюю ввиду бомбардировку очереди сообщений окна сообщениями от 272 устройств, особеннопри их активности) не будет тормозить работу пользователя с GUI. Лучше, но и сложнее сделать как предлагали выше, а именно

1) есть GUI работающий в смоем потоке
2) сервер слушает в другом отдельном потоке запросы на соединение
3) по приходу запроса создаем отдельный поток в котором осуществляется работа с конкретным клиентом, данное соединение пинуется и при завершении общения сторон (короректно или не корректно) поток завершает

вот при таком раскладе все будет как часы (неоднократно проверено). Естессно надо все как следует обернуть ))) У меня все есть ))) полностью слолюшн дать не могу, но сложные момент могу мммм продемонстрировать...

Да, сразу предупреждаю, там чистый API ни какого MFC и т.п.
Записан

С уважением Lapulya
Алексей++
глобальный и пушистый
Глобальный модератор

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


« Ответ #11 : 17-05-2008 07:33 » 

Да, сразу предупреждаю, там чистый API ни какого MFC и т.п.

MFC - легко Улыбаюсь Класс CAsyncSocket. И оборачивать не нужно, и потоки сами сделаются Улыбаюсь
Записан

pups
Гость
« Ответ #12 : 14-01-2009 03:13 » 

Прошу консультации опытных специалистов по CAsyncSocket.

Моя задача:
Написать приложение КЛИЕНТ, который будет  забирать у сервера миллион (или более) "единиц" информации в короткие сроки. При этом размер получаемой информации (одного запроса) колеблется от 0 до 100 (и более) мегабайт. Команды при обращению к серверу все различные, но в некоторых случаях имеют цикличность.

Пример работы моего клиента:
У нас есть события, которые  вызываются системой при работе клиента, это Receive. Это событие происходит когда серверу есть что отдать для клиента. Рассмотрим пример работы клиента:

... Receive()
{
// В этой функции мы должны получить данные от сервера (функция вызывается автоматически событиями, если сервер что то отдает)
// Создали буфер для получения сообщения
// Получили сообщение или часть сообщения от сервера т.к. размера буфера может не хватить
// и функция будет вызвана (событием) повторно для получения оставшейся части.
// т.е. функция будет вызвана столько раз, пока не получим всю информацию по запросу.
}

... Send()
{
while(...)
{
// Отправляем запрос на сервер
// Режим ожидания пока не получим полностью информацию на текущий запрос (при этом обрабатываем все системные события)
}
}

ВОПРОС: Как получить (создать) событие, которое сообщит, что данные текущего запроса от сервера уже получены полностью?
т.е. если мы не дождемся получения оставшейся части и отправим следующий запрос к серверу, то мы его перегрузим, а нам нужно забрать от сервера еще много информации с минимальными задержками по времени.  Есть какие то события, которые сообщат мне, что текущее сообщение получено полностью?
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

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


« Ответ #13 : 14-01-2009 04:55 » 

pups, нет такого события, которое покажет, что ВСЕ данные пришли. Происходит несколько иначе:

произведи свой класс от CAsyncSocket (лучше визардом - удобнее будет потом виртуальные функции переопределить)
Код:
class CMyS : public CAsyncSocket
{
};


для клиентского сокета при помощи AsyncSelect установи флаги

Код:
AsyncSelect(FD_READ|FD_CONNECT|FD_CLOSE);

таким образом,
1) виртуальная функция OnClose будет вызываться, когда сокет (или удалённая пара) разорвал соединение
2) виртуальная функция OnConnect будет вызываться, когда сервер подключил сокет

   и самое для тебя интересное:

3) виртуальная функция OnReceive будет вызываться, когда система имеет принятые от сервера данные, которые ещё не считаны твоим сокетом
Далее происходит следующее
  а) если в OnReceive не делать ничего, то эта функция так и будет постоянно вызываться, так как ещё есть данные, которые ты не считал
  б) если запретить обработку сообщений ( AsyncSelect(/*FD_READ*/0|FD_CONNECT|FD_CLOSE); ) то больше до разрешения эта функция не вызовется. Но так делать не нужно тебе Улыбаюсь
  в) можно вызвать CAsyncSocket::Receive() , чтоб принять часть данных в твой приёмный буфер. Функция - виртуальная, поэтому можно вызвать и просто Receive(), а можно вообще переопределить у себя в классе. Мне пока хватало просто вызвать родную функцию CAsyncSocket
Код:
void CMyS::OnReceive(int nErrorCode) 
{
//имеются ещё не принятые данные

//принять данные
{
//BYTE* m_ReadBuf - твой приёмный буфер
//DWORD m_dwdReadBufLen - длина этого буфера

int nRead=0;

nRead=CAsyncSocket::Receive(m_ReadBuf,m_dwdReadBufLen,0);

if(nRead==SOCKET_ERROR || nRead<=0)
{
//НЕТ ДАННЫХ или какой то косяк
}
else
{
//в буфере m_ReadBuf находятся nRead байт новых данных
}
}

CAsyncSocket::OnReceive(nErrorCode);
}

просто определить, что получены ВСЕ данные, не выйдет. К примеру, сервер послал тебе пакет 100 метров , затем пакет 1 метр. Ты примешь, возможно, сразу 101 метр. Как разделять пакеты - это уже твоя задача, ты читаешь данные небольшими кусками (скажем по 2 метра), отдаёшь их в накопительный буфер в своей основной программе. Программа после каждого принятого куска определяет, получен ли осмысленный пакет, если да  -она его обрабатывает и удаляет из накопительного буфера, смещая оставщийся конец ещё не докаченных данных в начало накопительного буфера.
Для чёткого разделения пакетов надо придумывать свой протокол

« Последнее редактирование: 14-01-2009 05:07 от Алексей1153++ » Записан

pups
Гость
« Ответ #14 : 14-01-2009 05:56 » 

pups, нет такого события, которое покажет, что ВСЕ данные пришли. Происходит несколько иначе:
... СКИП ...
просто определить, что получены ВСЕ данные, не выйдет. К примеру, сервер послал тебе пакет 100 метров , затем пакет 1 метр. Ты примешь, возможно, сразу 101 метр. Как разделять пакеты - это уже твоя задача, ты читаешь данные небольшими кусками (скажем по 2 метра), отдаёшь их в накопительный буфер в своей основной программе. Программа после каждого принятого куска определяет, получен ли осмысленный пакет, если да  -она его обрабатывает и удаляет из накопительного буфера, смещая оставщийся конец ещё не докаченных данных в начало накопительного буфера.
Для чёткого разделения пакетов надо придумывать свой протокол



в том то и вопрос! как разделить?! Улыбаюсь то что вы описали все работает как часы! я даже пробовал реализацию такую:
если размер моего буфера больше чем размер принятого пакета то это последняя передача.

_но_ сервера юникс (или ...) сами организуют (определяют) размер пакета в зависимости от своей загруженности (или на то есть другие причины) т.е. может получится так, что я определил размер буфера 1024, а сервер мне сначала отдает 900 байт, а потом шлет по 1024. это уже проверено.

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

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

буду благодарен за любые (полезные) рекомендации.

зы. сейчас читаю мсдн chapter 7: winsock basics. там что то описывается про это, но так плохо описано, что есть предположение, что писал человек, который сам плавает в этом вопросе. при наличии знаний, там писать нужно три строчки, а писатель проявил свою "поэтическую вольность" и рассказал обо всем, но только не о том, что нужно.
« Последнее редактирование: 14-01-2009 06:06 от Алексей1153++ » Записан
Алексей++
глобальный и пушистый
Глобальный модератор

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


« Ответ #15 : 14-01-2009 06:11 » 

разделить как - свой протокол придумать. Например, я вот это использую такой
https://forum.shelek.ru/index.php/topic,15504.0.html

но можешь что то своё придумать ) Например 4 байта - длина пакета, потом пакет, потом CRC 2 байта

Записан

pups
Гость
« Ответ #16 : 14-01-2009 07:06 » 

разделить как - свой протокол придумать. Например, я вот это использую такой
https://forum.shelek.ru/index.php/topic,15504.0.html
но можешь что то своё придумать ) Например 4 байта - длина пакета, потом пакет, потом CRC 2 байта

Во во! Майкрософт тоже это рекомендует:

Things get a little complicated if your message sizes vary. It is necessary to impose your own protocol to let the receiver know how big the forthcoming message will be. For example, the first 4 bytes written to the receiver will always be the integer size in bytes of the forthcoming message. The receiver will start every read by looking at the first 4 bytes, converting them to an integer, and determining how many additional bytes that message comprises.

Но я понятия не имею как создать свой протокол. Я его никогда их не делал. Тем более, что не известно как он себя поведет с большими обьемами данных и со всей прочей лабудой. Это мне придется неделю писать протокол, потом месяц отлавливать в нем ошибки ....

Может можно как-то получить (узнать) состояние сокета? Зная состояние сокета, можно создавать свои события.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

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


« Ответ #17 : 14-01-2009 08:00 » 

Цитата
Но я понятия не имею как создать свой протокол

взять лист бумаги и расписать структуру протокола. Ну вот, самое простое и не замороченное:
Код:
#pragma pack(push,1)

struct s_MyProtocolCRC
{
friend struct s_MyProtocolHeader;
private:
WORD wCRC;  //контрольная сумма всего пакета (без учёта байтов CRC, естественно)

public:
void FillCRC(const void* pData, DWORD dwdLen)
{
wCRC=функция_подсчёта_контрольной_суммы(pData,dwdLen);
}

s_MyProtocolCRC():wCRC(0){}

s_MyProtocolCRC(const void* pData, DWORD dwdLen)
{
FillCRC(pData,dwdLen);
}

bool CheckCRC(WORD wCRCforControl) const
{
return wCRCforControl==wCRC;
}
};

struct s_MyProtocolHeader
{
enum{e_sign=0x88};//сигнатура-константа

BYTE bySign; // сигнатура
DWORD dwdLen_H_DATA_CRC;// длина всего пакета (с учётом заголовка и CRC)

s_MyProtocolHeader(DWORD dwdDataLen):bySign(e_sign)
{
dwdLen_H_DATA_CRC=sizeof(*this)+dwdDataLen+sizeof(s_MyProtocolCRC);
}

bool CheckSign() const
{
return bySign==e_sign;
}
};

#pragma pack(pop)


шлём данные
Код:
//BYTE* pBuf - буфер с данными для передачи
//DWORD dwdLen - длина данных для передачи

s_MyProtocolHeader hdr(dwdLen);
s_MyProtocolCRC crc(pBuf,dwdLen);

CAsyncSocket::Send(&hdr,sizeof(hdr),0);
CAsyncSocket::Send(pBuf,dwdLen,0);
CAsyncSocket::Send(&crc,sizeof(crc),0);

принимаем данные
Код:
BYTE* pBuf;// - буфер с некими накопленными принятыми данными
DWORD dwdLen;// - длина данных


DWORD dwdProcessed=0;
for(;;)
{
const s_MyProtocolHeader* phdr=(s_MyProtocolHeader*)pBuf;
//контроль на достаточную длину для заголовка
if(dwdLen<sizeof(*phdr))break;
//контроль сигнатуры
if(!phdr->CheckSign())break;

//контроль на достаточную длину
if(dwdLen<phdr->dwdLen_H_DATA_CRC)break;

const s_MyProtocolCRC* pCRC=0;

const void* pData=phdr+sizeof(*phdr);
const DWORD dwdDataLen=phdr->dwdLen_H_DATA_CRC-sizeof(*phdr)-sizeof(*pCRC);

pCRC=(s_MyProtocolCRC*)(((BYTE*)pData)+dwdDataLen);

WORD crc=функция_подсчёта_контрольной_суммы(pData,dwdDataLen);
if(!pCRC->CheckCRC(crc))break;

dwdProcessed=phdr->dwdLen_H_DATA_CRC;

//pData - данные
//dwdDataLen - их длина

//обработка данных
//...

break;
}

//из принятого обработано dwdProcessed байт
Записан

McZim
Команда клуба

ru
Offline Offline
Пол: Мужской
Я странный


WWW
« Ответ #18 : 14-01-2009 08:07 » 

Цитата
offtop

Алексей1153++,
Цитата
шлём данные

 Под столом

у меня шлём, прочиталось как шлЕм, сижу и думаю, какой такой шлем?
Записан

The CBO without stats is like a morning without coffee. (c) T.Kyte.
Вад
Модератор

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

« Ответ #19 : 14-01-2009 08:24 » 

Подчеркну на всякий случай: нужен именно транспортный протокол над TCP. По сути, всего лишь способ сигнализации о начале пакета, его размере и типе (если нужно). Можно ещё контрольную сумму передавать, например.
Когда приходилось делать что-то подобное, обычно хватало простой заголовочной структуры для пакета, после которой уже передавались основные данные.
« Последнее редактирование: 14-01-2009 08:25 от Вад » Записан
Алексей++
глобальный и пушистый
Глобальный модератор

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


« Ответ #20 : 14-01-2009 09:02 » 

McZim, может сказывается, что ты букафку "ё" не уважаешь? Улыбаюсь)
Записан

lapulya
Молодой специалист

ru
Offline Offline

« Ответ #21 : 14-01-2009 09:13 » 

Я может задачи не понял, но почему мы не посылать клиенту в самом начале размер пересылаемого "пакета" данных в байтах, а на клиенте при приеме просто считать принятый объем, и если пришло не все, значит надо ждать оставшиеся данные. Это самый что ни наесть стандартный прием. И MFC не нужен... да простит меня пушистый за такое Улыбаюсь... пример как это реализовать только на моей памяти я указывал тут раза два...
Записан

С уважением Lapulya
Вад
Модератор

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

« Ответ #22 : 14-01-2009 09:19 » 

lapulya, собственно, я примерно о том же Улыбаюсь
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

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


« Ответ #23 : 14-01-2009 09:21 » 

lapulya, да никто не обижается, кто чем привык, тем и пользуется ) Если реализовывать в железяке - то да, по байтикам проще. А в компутере озу много, можно сильно не изголяться )

Цитата
и если пришло не все, значит надо ждать оставшиеся данные
а в примере у меня так и есть, просто тонкости там не прописаны, это ж отлаживать надо

ну а MFC тут лишь для удобства, если хочется и много времени свободного - сокеты в руки и вперёд ) Всё один к одному так же будет, только дольше писать
« Последнее редактирование: 14-01-2009 09:23 от Алексей1153++ » Записан

lapulya
Молодой специалист

ru
Offline Offline

« Ответ #24 : 14-01-2009 09:30 » 

Алексей1153++, ну у тебя там очень много букав написано))) а у меня весь код просто состоит в цикле с recv и выходом их цикла по считыванию необходимого количества информации (кстати не понял причем тут железка, я про программу, которая может работать где угодно, более того, товарищ pups писал о приеме миллионов запросов в короткие сроки причем каждый "пакет" может быть 100 Мб и более, тут с ОЗУ и надорваться можно, придется еще и на диск скидывать ну или уж я не знаю что там за конфигурация аппаратного обеспечения)
« Последнее редактирование: 14-01-2009 09:33 от lapulya » Записан

С уважением Lapulya
Алексей++
глобальный и пушистый
Глобальный модератор

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


« Ответ #25 : 14-01-2009 09:37 » 

Цитата
ну у тебя там очень много букав написано)))
вовсе не много, для интереса скомпилируй и посмотри ассеимблерный код Улыбаюсь

Цитата
тут с ОЗУ и надорваться можно, придется еще и на диск скидывать
а всё зависит не от клиента вовсе, а от того, как сервер будет данные присылать. Согласен ? Улыбаюсь Например, не пакет с 100 сообщениями, а 100 сообщений друг за другом.
Записан

lapulya
Молодой специалист

ru
Offline Offline

« Ответ #26 : 14-01-2009 09:57 » 

Ну я не про ассемблерный код, а про прикладной на с/с++, вот мой, он короче и показывает суть
Код:
	int full_length; // длина пакета в байтах (передано с сервера или определена протоколом)
char * buffer; // выделенный буфер данных размера full_length

int rev_length = 0;
nParam = sizeof( SOCKADDR_IN );
while (rev_length < full_length)
{
int recv_now = recvfrom( sock, buffer + rev_length, full_length - rev_length, 0, &addr, &nParam );
if (recv_now == SOCKET_ERROR )
{
TRACE( WSAGetLastError() );
continue;
}

rev_length += recv_now;
}
Записан

С уважением Lapulya
Алексей++
глобальный и пушистый
Глобальный модератор

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


« Ответ #27 : 14-01-2009 10:07 » 

так у меня сам протокол реализован практически )
Записан

lapulya
Молодой специалист

ru
Offline Offline

« Ответ #28 : 14-01-2009 10:17 » 

Я по этому и написал "много букав - не осилил", я же не говорю, что это не рабочий вариант, просто я так понял пупсу нужна концепция и я, а точнее Вад чуть раньше предложил наиболее простую. Это также протокол, только он много проще - всего надо передавать в начале пакета (первыми 4 байтами ну или как договоримся) размер данных пакета и все.
Записан

С уважением Lapulya
pups
Гость
« Ответ #29 : 14-01-2009 20:53 » 

так у меня сам протокол реализован практически )

Алексей. Можно ли мне обьяснить "крестьянину", что Вы подразумеваете под словом "протокол"? Прошу Вас мне "на пальцах" обьяснить. Я совершенно не понимаю о чем идет речь. В моем понимании протокол, это формат передаваемых данных. Если я создам свой формат передачи, то на сервере должен быть такой же формат, иначе сервер меня не поймет. А т.к. к серверу я не имею доступа, то наверное использование протокола не приемлемо?
Я не понимаю о каком протоколе идет речь и на каком уровне предется писать.
Как я увидел из Вашего примера, то .... ничего не понял. Вы используете базовый класс Асинхронного сокета, создаете какие то структуры которые как я понимаю должны содержать структуру протокола.

Если Вы меня понимаете, прошу Вас обьясните мне дураку "на пальцах" теорию того что Вы предлагаете, чтобы мне и окружающим было понятно.

Этот вопрос очень насущный и актуальный. Много людей пытаются реализовать данную задачу. Я этот вопрос ковыряю больше месяца, перерыл кучу классов на кодепрожекте, коде гуру и т.д.

P.S. Для всех: Очень прошу не создавать в теме флейм, чтобы обсуждение основного вопроса не переросло в обсуждение других вопросов, которые уже давно решены и не интересны.
Задача разделить  поступаемый поток данных от сервера, с целью контроля передачи очереди сообщений.
Буду очень благодарен за любые рабочие варианты (благодарности типа заметок внутри программы с благодарностью о помощи, пива и т.д. предусматриваются и даже не упоминаются).

ЗЫ2. Покрутил предлагаемый вариант lapulya, но не смог ему ума придать. Он сразу возвращает минус 1 и ничего не принимает. Последние два параметра не обязательные и я передавал туда NULL.
Записан
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #30 : 14-01-2009 21:03 » 

pups, Тут дело вот в чем, протокол TCP потоковый, поэтому если протокола нет (вод протоколом имеется ввиду хоть какие-то правила передачи и приема данных), то ничего получить или принять нельзя. Т.е. если с сервера начинает как из крана литься данные и ты не в состоянии ни как понять когда они кончатся (исходя из самих данных), то написать клиент-серверное приложение нельзя!!!
Записан

С уважением Lapulya
pups
Гость
« Ответ #31 : 14-01-2009 21:04 » 

Я по этому и написал "много букав - не осилил", я же не говорю, что это не рабочий вариант, просто я так понял пупсу нужна концепция и я, а точнее Вад чуть раньше предложил наиболее простую. Это также протокол, только он много проще - всего надо передавать в начале пакета (первыми 4 байтами ну или как договоримся) размер данных пакета и все.
Теорию я понял, даже сам пробовал это реализовать, но использовать GetSockOpt с параметром SO_RCVBUF не получается. Нифига этот GetSockOpt не работает. Если бы работал, то я бы знал размер передаваемых данных и закрутил бы цикл.

То же самое предлагает микрософт в мсдн:
   idx = 0;

    while (nLeft > 0)
   {
      ret = recv(m_sConnectSocket, &recvbuff[idx], nLeft, 0);
      
      if (ret == SOCKET_ERROR)
      {
         goto end_fu;
        // Error
      }
      idx += ret;
      nLeft -= ret;
   }
Но мы не знаем размер поступаемых данных nLeft. Если бы знать точно размер в байтах, то вопрос был бы снят сам собой.
Записан
Вад
Модератор

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

« Ответ #32 : 14-01-2009 21:06 » 

pups, ок, если сервер у тебя уже есть - протокол отбрасываем, тебе нужно поддерживать тот, который предоставляется сервером. Точнее, так: при закачке, есть у тебя возможность узнать размер получаемой информации для конкретного сеанса до начала самой закачки? Или всё, что у тебя есть - это порт на сервере, куда ты подключаешься, и тебе льют данные? Если последнее - то что делает сервер потом, неужели оставляет соединение открытым?
Словом, нужна конкретика о взаимодействии с сервером в рамках сеанса.
Записан
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #33 : 14-01-2009 21:08 » 

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

С уважением Lapulya
pups
Гость
« Ответ #34 : 14-01-2009 21:09 » 

pups, Тут дело вот в чем, протокол TCP потоковый, поэтому если протокола нет (вод протоколом имеется ввиду хоть какие-то правила передачи и приема данных), то ничего получить или принять нельзя. Т.е. если с сервера начинает как из крана литься данные и ты не в состоянии ни как понять когда они кончатся (исходя из самих данных), то написать клиент-серверное приложение нельзя!!!

Согласен. Откуда берется событие получения данных? Событие берется от того, что изменилось состояние сокета. В зависимости от состояния определено событие. Тогда как получить текущее состояние сокета? Если состояние сокета "в покое", то я могу передавать данные. Я же отслеживаю все события системы (реагирую на них) в режиме ожидания, значит могу прикрутить проверку состояния сокета. НО КАК СДЕЛАТЬ ПРОВЕРКУ? Это было бы идеальным решением.

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

Тогда это должен быть протокол работы сокета, а не протокол передачи данных. Я правильно понимаю?

Дополнительно. И как это все реализовать? Улыбаюсь У меня мозгов не хватает. Я это никогда не делал и понятия не имею с какой стороны "подойти" к данному вопросу.
« Последнее редактирование: 15-01-2009 04:33 от Алексей1153++ » Записан
Вад
Модератор

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

« Ответ #35 : 14-01-2009 21:17 » 

pups, не-не-не. Когда уже из сокета "течёт", ты не можешь лишь по одному "течёт" и "перестало течь" сделать вывод, что данные кончились. Для определения, поступили в сокет данные или нет, есть select (и должен быть аналог - а точнее, обёртка к нему - у AsyncSocket). Точнее, select можно вызывать сразу для массива сокетов. Впрочем, если это единственное, что тебе нужно...
« Последнее редактирование: 14-01-2009 21:19 от Вад » Записан
pups
Гость
« Ответ #36 : 14-01-2009 22:00 » 

Мы говорим о AsyncSelect или просто о select? Пол моему это одно и то же. Я использую все события, но их там не достаточно чтобы узнать когда кончились данные.
Акцепт - используетесся только на сервере, ждет поступления сообщений.
Клосе - Событие когда прервали соединение.
Коннект - когда соединились.
Аут оф Банд дата - для служебных сообщений (инфы по нему очень мало) т.к. даже майкрософт говорит, что люди его отказываются использовать, а создают паралельные сокеты.
Рецейв - Получаем
Сенд - отправляем.

Других событий нет, а этих не достаточно для решения моей задачи. Как я понимаю АсинкСокет происходит из Ц обьект. Более нижнего уровня нет. Далее из Асинк сокета выходит клас Ц Сокет.

По этому если писать что либо связанное с большим количеством событий, то это на уровне Ц обьекта?
Чего то у меня мозги дымят. У меня уже 4 утра. Иду спать.

Что Вы посоветуете использовать? Вы наглядно представляете решение данной задачи? Вы можете мне обьяснить решение?
Записан
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #37 : 14-01-2009 23:52 » 

pups, честно говоря про MFC ничего не знаю, особенно про сокеты, но на уровне API понять по сокету когда кончились данные нельзя. Никак нельзя, вот хоть тресни...

Поэтому еще раз говорю протокол обязателен. Обычно или скажем так, часто делают так: надо послать сообщение (пакет) размером в "к" байт. Что делают, а вот что - сначала шлют данные размером в sizeof(long) (причем на обоих хостах они должны совпадать). на принимающей стороне в цикле принимаем ровно sizeof(long) байт (как это делается я показывал), приняв их и скастовав в long смотрим каков же размер "пакета" (заметь слово пакета я пишу в кавычках, потому как нет в tcp понятия пакет - это потоковый протокол, у меня язык отсох это повторять на форуме каждый второй интересующийся сокетами этого недопонимает, но это я не в обиду, а так между прочим). Узнав размер пакета опять в цикле его принимаем, пока не примем весь или пока не порвется соединение ил не получим какую нить ошибку. вот и вся наука. Но это все хорошо, когда сервер (который я так понял ты изменить не можешь), следует описанному правилу (который можно смело назвать и протоколом). В любом случае какой-то протокол (читай правила отправки и приема данных) сервер должен реализовать, иначе никак...
Записан

С уважением Lapulya
Алексей++
глобальный и пушистый
Глобальный модератор

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


« Ответ #38 : 15-01-2009 04:36 » 

pups, lapulya, забудьте про MFC - не MFC . CAsyncSocket внутри ничем не отличается от обычных сокетов (он же их и использует) , просто обработка сообщений более удобная.

pups, пока не узнаешь протокол, который использует сервер - помочь никто ничем не сможет, это факт Улыбаюсь
Если устал - надо поспать, работоспособность резко падает, когда так

Записан

pups
Гость
« Ответ #39 : 15-01-2009 06:29 » 

pups, lapulya, забудьте про MFC - не MFC . CAsyncSocket внутри ничем не отличается от обычных сокетов (он же их и использует) , просто обработка сообщений более удобная.

Вы меня окончательно запутали. Есть почтовый сервер. Нужно получить с него миллион писем. Все они разного размера. Как мне узнать, что предыдущее письмо получено, чтобы отправить очередной запрос? Протокол POP3. Не уж то об этом люди не подумали? У меня не получается получить информацию, что предыдущее письмо окончательно получено.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

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


« Ответ #40 : 15-01-2009 06:31 » 

pups, ну вот, уже прогресс )) Протокол известен. Бери описание и вперёд - посылай запросы, получай ответы. с POP3 я не работал, только отправку писем делал, поэтому тут уже не подскажу

http://ru.wikipedia.org/wiki/POP3
« Последнее редактирование: 15-01-2009 06:34 от Алексей1153++ » Записан

RXL
Технический
Администратор

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

WWW
« Ответ #41 : 15-01-2009 06:39 » 

pups, стандарт читал?
RFC1939 - Post Office Protocol - Version 3
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
pups
Гость
« Ответ #42 : 15-01-2009 07:26 » 

pups, стандарт читал?
RFC1939 - Post Office Protocol - Version 3

Знаю этот протокол как "Отче наш ...". Если Вы говорите о получении размера письма по номеру, то этот номер иногда не проходит. Некоторые сервера не поддерживают эту команду. Проверено и даже не обсуждается. Например майл.ру бывает ВРЕМЕНАМИ, что не поддерживате эту команду.  Что то нужно другое намудрить. Программа подразумевает круглосуточную работу нужна максимальная стабильность.
Записан
pups
Гость
« Ответ #43 : 15-01-2009 07:28 » 

pups, ну вот, уже прогресс )) Протокол известен. Бери описание и вперёд - посылай запросы, получай ответы. с POP3 я не работал, только отправку писем делал, поэтому тут уже не подскажу
http://ru.wikipedia.org/wiki/POP3

Отправку делал по SMTP с авторизацией или если протокол открыт?
Записан
RXL
Технический
Администратор

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

WWW
« Ответ #44 : 15-01-2009 07:34 » 

pups, каждое сообщение завершается строкой с точкой - используй этот маркер.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
pups
Гость
« Ответ #45 : 15-01-2009 08:38 » 

Я ранее уже об этом писал.  Эта точка может быть использована тыщу раз в одном письме. Нельзя о нее опираться.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

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


« Ответ #46 : 15-01-2009 08:45 » 

pups,
Цитата
SMTP с авторизацией
да, это же тоже стандарт. А адрес smtp-сервера у меня в программе вообще юзер вводил сам

Я ранее уже об этом писал.  Эта точка может быть использована тыщу раз в одном письме. Нельзя о нее опираться.
читал говоришь ? ) Точка то тосле ентера

Цитата
When all lines of the response have been sent, a
   final line is sent, consisting of a termination octet (decimal code
   046, ".") and a CRLF pair.
« Последнее редактирование: 15-01-2009 08:48 от Алексей1153++ » Записан

pups
Гость
« Ответ #47 : 15-01-2009 08:51 » 

читал говоришь ? ) Точка то тосле ентера

Тема закрыта. Спасибо. Простите что побеспокоил.
Записан
Вад
Модератор

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

« Ответ #48 : 15-01-2009 08:58 » 

Я ранее уже об этом писал.  Эта точка может быть использована тыщу раз в одном письме. Нельзя о нее опираться.
Может, я чего не понимаю. Но команда LIST, да и RETR, судя по спецификации, отдаёт число октетов (читай: размер) каждого письма. Неужели не прочитать столько октетов, сколько сказано?
Записан
RXL
Технический
Администратор

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

WWW
« Ответ #49 : 15-01-2009 10:04 » 

Вад, https://forum.shelek.ru/index.php/topic,14734.msg196536.html#msg196536
Попадаются дурные почтовики.

pups, точка - одна на строке - в теле письма быть не может, т.к. SMTP использует тотже маркер приотсылке письма. По это причине текст письма, который может конфликтовать, кодируют в base64 и т.п.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
pups
Гость
« Ответ #50 : 15-01-2009 10:05 » 

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

Спасибо за помощь. Тема закрыта.
Записан
Страниц: 1 2 [Все]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines