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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Sockets обработка событий 
:(
    Опции темы
Hellriser
Дата 4.8.2009, 13:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Всем доброго времени суток, помогите разобраться с обработкой событий.
Есть сл. код:
Код

char* __fastcall Socket::Request(char* input)
{
        int count(0), bytes, length, res;
        char buffer[8*1024];
        WSANETWORKEVENTS SockProcessEv;

        length = strlen(input);

        WSACloseEvent(SockNtEv);
        SockNtEv = WSACreateEvent();

        res = WSAEventSelect(Sock, SockNtEv, (FD_READ | FD_WRITE));
        if(res == 0)
                WSAResetEvent(SockNtEv);
        while(true)
        {
                WSAWaitForMultipleEvents(1, &SockNtEv, false, 200, false); 

                WSAEnumNetworkEvents(Sock, SockNtEv, &SockProcessEv);
                if((SockProcessEv.lNetworkEvents & FD_WRITE) && (SockProcessEv.iErrorCode[FD_WRITE_BIT] == 0))
                {
                        do
                        {
                                bytes = send(Sock, input + count, length - count, 0);
                                if (bytes == SOCKET_ERROR)
                                {
                                        if(WSAGetLastError() != WSAEWOULDBLOCK)
                                        {
                                                break;
                                        }
                                }
                                count += bytes;
                        }
                        while(count < length);
                }
                if((SockProcessEv.lNetworkEvents & FD_READ) && (SockProcessEv.iErrorCode[FD_READ_BIT] == 0))
                {
                        while(true)
                        {
                                bytes = recv(Sock, (char*)&buffer, sizeof(buffer), 0);
                                if (bytes == SOCKET_ERROR)
                                {
                                        if(WSAGetLastError() == WSAEWOULDBLOCK)
                                        {
                                                return buffer;
                                        }
                                }
                        }
                }
        }
}


проблема в том, что при первом вызове всё срабатывает, события устанавливаются, а при дальнейших вызовах 
Код
SockProcessEv.lNetworkEvents
 устанавливается в нуль и соответственно цикл становится действительно бесконечным :(

P.S. Модераторы, прошу прощения, что тему перепутал.

Это сообщение отредактировал(а) Hellriser - 4.8.2009, 13:58
PM MAIL   Вверх
dumb
Дата 5.8.2009, 01:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


sceloglauxalbifacies
****


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

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



если кратко: неправильно все, от начала и до конца.

по пунктам:
  •  непонимание работы сетевых событий. FD_WRITE - событие, разрешающее продолжение посылки данных. изначально устанавливается после соединения, впоследствии - после ситуации переполнения внутреннего буфера посылаемых данных и возврата функцией send/sendto/... кода WSAEWOULDBLOCK. т.е. нужно слать(send) данные, пока не вернется WSAEWOULDBLOCK, потом вставать на ожидание FD_WRITE, и по приходу оного продолжать посылку.
  •  прием данных тоже сделан неверно.
  •  функции имеют коды возврата, ага. в твоем коде код возврата проверяется только в одном случае, да и то - производимое действие бессмысленно: эвент создается изначально сброшенным.
  •  почему нет обработки разрыва соединения?
  •  возврат локального буфера, который после выхода из функции "разрушается" - char buffer[8*1024]; / return buffer;
  •  ...


M
dumb
Тема переезжает в C/C++: Сети

PM MAIL   Вверх
Hellriser
Дата 15.8.2009, 15:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



господа подскажите пожалуйста как правильно организовать прием данных, делаю так

Код

                if((SockProcessEv.lNetworkEvents & FD_READ) && (SockProcessEv.iErrorCode[FD_READ_BIT] == 0))
                {
                        do
                        {
                                bytes = recv(Sock, (char*)&buffer, sizeof(buffer), 0);
                                if (bytes == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)
                                {
                                        {
                                                MessageDlg("Error5 code: "+IntToStr(WSAGetLastError()), mtError, TMsgDlgButtons() << mbOK, 0);
                                                return;
                                        }
                                }
                                else if(bytes == 0)
                                        return;

                                resp+=buffer;
                        }while(WSAGetLastError() != WSAEWOULDBLOCK);

                        Response = new char(resp.Length());
                        Response = resp.c_str();
                }



но ответ приходит двумя пакетами, т.о. после чтения первого пакета происходит WSAEWOULDBLOCK на данный момент делаю возврат к ожиданию FD_READ и ставлю таймаут, но при сильной загрузке канала или сервера выход по таймауту может произойти раньше чем вторая часть ответа придет, с другой стороны при большом значении таймаута получается лишние задержки в работе приложения
PM MAIL   Вверх
Олег2005
Дата 15.8.2009, 17:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 421
Регистрация: 26.5.2005
Где: Рига Латвия

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



Поясните, как потоковая передача TCP может базироваться на пакетах?
recv() принимает поток байтов - до прихода FIN с той стороны.
Скорее всего у вас неверна логика использования recv()

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


Новичок



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

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



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

Сори что криво изъясняюсь, уже запарился :(
PM MAIL   Вверх
Олег2005
Дата 16.8.2009, 20:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 421
Регистрация: 26.5.2005
Где: Рига Латвия

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



Цитата(Hellriser @  15.8.2009,  19:34 Найти цитируемый пост)
Сначала сервер присылает ответ что команда принята, а потом уже начинает отправку данных, т.е получается что выбираю строку ответа, что команда принята и на этом как бы буфере все, данных нет, соответственно возникает ошибка нет данных для чтения если делаю возврат к ожиданию события, то все данные принимаются. 

Таким образом, сервер передает вам небольшую порцию - свой ответ. Соединение он не закрывает, а вы считываете из буфера TCP все что пришло.
Событие FD_READ (что-то есть для чтения в буфере TCP)сбрасывается, так как буфер приема пуст.
То, что последующий запуск recv() возвращает  WSAEWOULDBLOCK, это верно - сокет то у вас асинхронный, а вот сервер еще не успел по сети прислать вторую порцию данных, и FD_READ еще не возникло.
Наверно так?
Тут ничего не поделаешь - увы, это сеть. Конечно же вы не знаете, когда придет следующая порция.
Тут наверно надо правильно обработать первый WSAEWOULDBLOCK - и после получения его вернуться на 
if((SockProcessEv.lNetworkEvents & FD_READ) && (SockProcessEv.iErrorCode[FD_READ_BIT] == 0))
Иначе точный тайм-аут не выставить, поэтому придется грузить процессор и выполнять этот IF в цикле  - столько раз, сколько надо.
Это такая мысль на ходу....
Если ваши правила обмена с сервером (протокол общения) это позволяют, то можно попробовать нечто в таком духе. 
Для уменьшения нагрузки при переключении контекстов можно такое чтение делать в отдельном потоке..... 

Это сообщение отредактировал(а) Олег2005 - 16.8.2009, 20:20
PM MAIL WWW MSN   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Сети | Следующая тема »


 




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


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

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