2009-09-02 4 views
0

Я использую модель ввода/вывода WSAEventSelect в сокетах Windows, и теперь я хочу знать, как я могу узнать, что мои операции отправки и получения отправили и получили все данные?Winsocks Отправить и получить

После того, как я это знаю, как мне создать способ, чтобы он полностью передавал данные? Любые примеры будут действительно оценены.

Вот код (пример кода из книги, которую я учусь у):

SOCKET SocketArray [WSA_MAXIMUM_WAIT_EVENTS]; 
WSAEVENT EventArray [WSA_MAXIMUM_WAIT_EVENTS], 
NewEvent; 
SOCKADDR_IN InternetAddr; 
SOCKET Accept, Listen; 
DWORD EventTotal = 0; 
DWORD Index, i; 
WSANETWORKEVENTS NetworkEvents; 


// Set up socket for listening etc... 
// .... 

NewEvent = WSACreateEvent(); 

WSAEventSelect(Listen, NewEvent, 
       FD_ACCEPT │ FD_CLOSE); 

listen(Listen, 5); 

SocketArray[EventTotal] = Listen; 
EventArray[EventTotal] = NewEvent; 
EventTotal++; 

while(TRUE) 
{ 
    // Wait for network events on all sockets 
    Index = WSAWaitForMultipleEvents(EventTotal, 
     EventArray, FALSE, WSA_INFINITE, FALSE); 
    Index = Index - WSA_WAIT_EVENT_0; 

    // Iterate through all events to see if more than one is signaled 
    for(i=Index; i < EventTotal ;i++ 
    { 
     Index = WSAWaitForMultipleEvents(1, &EventArray[i], TRUE, 1000, 
      FALSE); 
     if ((Index == WSA_WAIT_FAILED) ││ (Index == WSA_WAIT_TIMEOUT)) 
      continue; 
     else 
     { 
      Index = i; 
      WSAEnumNetworkEvents(
       SocketArray[Index], 
       EventArray[Index], 
       &NetworkEvents); 

      // Check for FD_ACCEPT messages  
      if (NetworkEvents.lNetworkEvents & FD_ACCEPT) 
      { 
       if (NetworkEvents.iErrorCode[FD_ACCEPT_BIT] != 0) 
       { 
        printf("FD_ACCEPT failed with error %d\n", 
         NetworkEvents.iErrorCode[FD_ACCEPT_BIT]); 
        break; 
       } 

       // Accept a new connection, and add it to the 
       // socket and event lists 
       Accept = accept(
        SocketArray[Index], 
        NULL, NULL); 

       NewEvent = WSACreateEvent(); 

       WSAEventSelect(Accept, NewEvent, 
        FD_READ │ FD_CLOSE); 

       EventArray[EventTotal] = NewEvent; 
       SocketArray[EventTotal] = Accept; 
       EventTotal++; 
       printf("Socket %d connected\n", Accept); 
      } 

      // Process FD_READ notification 
      if (NetworkEvents.lNetworkEvents & FD_READ) 
      { 
       if (NetworkEvents.iErrorCode[FD_READ_BIT] != 0) 
       { 
        printf("FD_READ failed with error %d\n", 
         NetworkEvents.iErrorCode[FD_READ_BIT]); 
        break; 
       } 

       // Read data from the socket 
       recv(SocketArray[Index - WSA_WAIT_EVENT_0], 
        buffer, sizeof(buffer), 0); 

       // here I do some processing on the data received 
       DoSomething(buffer); 

       // now I want to send data 
       send(SocketArray[Index - WSA_WAIT_EVENT_0], 
         buffer, sizeof(buffer), 0); 
       // how can I be assured that the data is sent completely 

      } 

      // FD_CLOSE handling here 
      // ...... 
      // ...... 
     } 
    } 
} 

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

** EDIT: ** См событие часть FD_READ

ответ

0

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

Именно поэтому большинство протоколов сообщают партнеру о том, сколько байтов он будет отправлен перед отправкой, или помещением границы в конце данных.

Об отправке необходимо знать буфер, который вы используете. Когда вы send(), он переходит в буфер (по умолчанию 64 Кбайт). send() возвращает количество байтов, помещенных в буфер, если его меньше, чем байты, которые вы пытались отправить, вам нужно будет выполнить его, чтобы повторить попытку в следующий раз, когда вы получите событие FD_WRITE.

Вы не можете быть уверены в том, сколько данных уже получено партнером, если оно не информирует вас (mIRC DDC делает это).

Не уверен, что это clearfyed ваших сомнений, надеюсь, что это помогло :)

+0

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

+0

Простой, вы ждете FD_WRITE :) – Havenard

+0

, так как я отправляю короткие сообщения (1, 2 байта). Я не буду получать еще одно событие FD_WRITE, если внутренний буфер не заполнен. – akif

0

Когда вы делаете ПРИЕМ, вам необходимо сохранить статус возврата, чтобы определить, были ли данные получены. recv возвращает количество полученных байтов, и я бы использовал флаг MSG_WAITALL вместо нуля, чтобы четвертый параметр получил все сообщение (в зависимости от размера буфера). Если возврат возврата статуса отрицательный, произошла ошибка некоторого характера, например, соединение было близко от другого конца или возникла другая проблема.

Что касается отправки, вы должны сохранить возвращаемое значение, так как оно также является статусом, но в этом случае нет флага для отправки всех данных перед возвратом. Вам нужно будет определить сумму отправки и настройки буфера и отправить размер на основе значения. Как и в случае с recv, отрицательное значение указывает на ошибку.

Я прочитал описания функций на веб-сайте Microsoft для recv и send для получения дополнительной информации о возвращаемых значениях и флагах.

+0

MSG_WAITALL предназначен для SOCK_DGRAM (UDP и RAW). SOCK_STREAM (TCP) будет зависать. – Havenard