Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > WSARecv


Автор: zss 26.1.2007, 10:32
создаю сокет
Код

SOCKET socket = WSASocket ( protocol, type, IPPROTO_TCP, NULL, 0, 0);

На этом сокете слушает сервер
Код

WORD index = WSAWaitForMultipleEvents (..., FALSE, 100, FALSE);
if ((index == WSA_WAIT_FAILED) || (index == WSA_WAIT_TIMEOUT))
{
    continue;
}
...
if (WSAEnumNetworkEvents (socket, event, ...) == SOCKET_ERROR)
{
   ...
}


На запросе сокет вываливает с ошибкой
Код

Операция на незаблокированном сокете не может быть завершена немедленно

Код ошибки 10035
Код

Resource temporarily unavailable. 
This error is returned from operations on nonblocking sockets that cannot be completed
immediately, for example recv when no data is queued to be read from the socket. It is a
nonfatal error, and the operation should be retried later. It is normal for WSAEWOULDBLOCK to be
reported as the result from calling connect on a nonblocking SOCK_STREAM socket, since some time must
elapse for the connection to be established.


Серверу приходит блок данных. Но перед ним идет заголовок. Он всегда одной длинны. В заголовке
передается как правило длинна блока.

Тоесть сначала сервер вычитывает заголовок. После определеяет длинну данных и вычитывает данные.
Так вот если клиент отсылает все сразу, то тогда работает.
А если он отсылает тоже кусками (тоесть сначала заголовок, а потом и блок), то сервер заголовок получает, 
а для того, чтоб получить данные ему приходится ждать (простейший Sleep(100) помог).

Почему так ? 

З.Ы. И еще. событие FD_READ говорит о том, что серверу например пришел запрос. 
Тоесть поймав это событие можно обменивать данными.

Когда сервер пытается отослать данные, то приходит FD_WRITE. Для чего это событие вообще нужно
если через него можно определить лишь что сервер что-то пульнул в сокет 

Автор: Dude03 26.1.2007, 14:34
Насколько мне известно, то так заканчивается recv на асинхронном сокете, если нечего читать.

Автор: zss 28.1.2007, 15:09
Dude03, да  уменя так и есть - сокет неблокирующий. Но как реализовать ожидание новых событий FD_READ & FD_WRITE ?

Автор: Dude03 28.1.2007, 15:16
Асинхронная работа через объект события 
Если в программе нет процедуры обработки сообщений, то можно воспользоваться объектами событий. В этом случае алгоритм работы будет несколько иной: 

Создать объект события с помощью функции WSACreateEvent. 
Выбрать сокет с помощью функции WSAEventSelect. 
Ожидать событие с помощью функции WSAWaitForMultipleEvents. 
Давайте подробно рассмотрим все функции, необходимые для работы с объектами событий. 

Первым делом следует создать событие с помощью функции WSACreateEvent. Функции не надо передавать никаких параметров, она просто возвращает новое событие типа WSAEVENT: 

Код

WSAEVENT WSACreateEvent(void); 


Теперь нужно связать сокет с этим объектом и указать события, которые нам нужны. Для этого используется функция WSAEventSelect: 

Код

int WSAEventSelect (
    SOCKET s,
    WSAEVENT hEventObject,
    long lNetworkEvents
    )


Первый параметр — это сокет, события которого нас интересуют. Второй параметр — объект события. Последний параметр — это необходимые события. В качестве последнего параметра можно указывать те же константы, что рассматривались для функции WSAAsyncSelect (все они начинаются с префикса FD_). 

Раньше вы уже встречались с функциями WaitForSingleObject и WaitForMultipleObjects, которые ожидают наступления события типа HANDLE. Для сетевых событий используется похожая функция с именем WSAWaitForMultipleEvents:

Код

DWORD WSAWaitForMultipleEvents (
    DWORD cEvents,
    const WSAEVENT FAR *lphEvents,
    BOOL fWaitAll,
    DWORD dwTimeOUT,
    BOOL fAlertable
    );



Давайте рассмотрим каждый параметр: 

cEvents — количество объектов событий, изменение состояния которых нужно ожидать. Чтобы узнать максимальное число, воспользуйтесь константой WSA_MAXIMUM_WAIT_EVENTS; 
lphEvents — массив объектов событий, которые нужно ожидать; 
fWaitAll — режим ожидания событий. Если указано TRUE, то функция ожидает, пока все события не сработают, иначе — после первого передает управление программе; 
dwTimeOUT — временной интервал в миллисекундах, в течение которого нужно ожидать события. Если в этом временном интервале не возникло события, то функция возвращает значение WSA_WAIT_TIMEOUT. Если нужно ожидать бесконечно, то можно указать константу WSA_INFINITE; 
fAlertable — параметр используется при перекрестном вводе/выводе, который я не рассматриваю в этой книге, поэтому указан FALSE. 
Чтобы узнать, какое событие из массива событий сработало, нужно вычесть из возвращенного функцией WSAWaitForMultipleEvents значения константу WSA_WAIT_EVENT_0. 

Прежде чем вызывать функцию WSAWaitForMultipieEvents, все события в массиве должны быть пустыми. Если хотя бы одно из них будет занято, то функция сразу вернет управление программе, и не будет ожидания. После выполнения функции отработавшие события становятся занятыми, и после обработки их надо освободить. Для этого используется функция WSAResetEvent: 

Код

BOOL WSAResetEvent (
    WSAEVENT hEvent
    );


Функция очищает состояние события, указанного в качестве единственного параметра. 

Когда событие уже не нужно, его необходимо закрыть. Для этого используется функция WSACloseEvent. Функции следует передать объект события, который необходимо закрыть: 

Код

BOOL WSACloseEvent (
    WSAEVENT hEvent
    );


Если закрытие прошло успешно, то функция возвращает TRUE, иначе — FALSE. 

откуда-то=)
Может не 
Код

WORD index = WSAWaitForMultipleEvents (..., FALSE, 100, FALSE);

а
Код

WORD index = WSAWaitForMultipleEvents (..., FALSE, WSA_INFINITE, FALSE);


Добавлено @ 15:30 
Цитата(zss @  26.1.2007,  10:32 Найти цитируемый пост)
Когда сервер пытается отослать данные, то приходит FD_WRITE. Для чего это событие вообще нужно
если через него можно определить лишь что сервер что-то пульнул в сокет  

А если у тебя с сокетом работает 2 потока и надо узнать когда другой что-то запишет туда?

Автор: zss 28.1.2007, 23:01
Dude03, спасибо за подробный ответ.

Но как все-таки ожидать. Может проще слушающий сокет сделать неблокирующим, а клиентскиу после WSAAccept блокирующим
и для него запускать отдельный поток. А после того как поток отработал - убивать сокет.

Но у меня почему-то после
Код

    SOCKET client = WSAAccept ( m_socket, (sockaddr*) &m_address,
                                &size, NULL, 0 );
    if (client == INVALID_SOCKET)
    {
        return false;
    }



клиент тоже оказывается неблокирующим. Почему ?

Автор: Dude03 28.1.2007, 23:07
Проще всего сделать через WSAAsyncSelect и сообщения Windows. Но там надо создать окно, которому и будет приходить сообщения.

Автор: zss 28.1.2007, 23:09
Цитата(Dude03 @  28.1.2007,  23:07 Найти цитируемый пост)
Проще всего сделать через WSAAsyncSelect и сообщения Windows. Но там надо создать окно, которому и будет приходить сообщения.

не - окна не пойдут - у меня сервис smile


Цитата(Dude03 @  28.1.2007,  15:16 Найти цитируемый пост)
А если у тебя с сокетом работает 2 потока и надо узнать когда другой что-то запишет туда?

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

Добавлено @ 23:10 
Я ведь могу только определить для какого сокета пришло событие

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)