2009-09-02 10 views
0

J'utilise le modèle d'E/S WSAEventSelect dans Windows Sockets et maintenant je veux savoir comment puis-je savoir que mes opérations d'envoi et de réception ont envoyé et reçu toutes les données? Après je le sais, comment devrais-je concevoir un moyen pour qu'il envoie les données complètement? Tous les exemples seraient vraiment appréciés.Winsocks Envoyer et recevoir

Voici le code (code exemple du livre J'apprends de):

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 
      // ...... 
      // ...... 
     } 
    } 
} 

Ce que je pensais, que je mettrais un drapeau booléen pour déterminer que la réception est terminée (le message avoir sa longueur préfixée), puis commencer à traiter ces données. Mais qu'en est-il envoyer()? Pouvez-vous s'il vous plaît me dire les possibilités.

** EDIT: ** Voir la partie de l'événement FD_READ

Répondre

0

À moins que le protocole (couche d'application), vous gérez vous donne des informations sur le nombre de données que vous êtes sur le point de recevoir, la seule façon de déterminer si il n'y a plus rien à recevoir quand le pair se déconnecte. Si le serveur arrête simplement d'envoyer, vous ne pouvez pas déterminer si c'est la fin ou si c'est juste occupé. Il se termine quand il se termine. Vous ne pouvez pas non plus déterminer si le serveur s'est déconnecté parce que c'est la fin ou parce que la connexion a été rompue.

C'est pourquoi la plupart des protocoles informent le pair sur le nombre d'octets qu'il va être envoyé avant de l'envoyer, ou en plaçant une limite à la fin des données. À propos de l'envoi, vous devez connaître le tampon que vous utilisez. Lorsque vous send(), il va à un tampon (avec 64 Ko par défaut). send() renvoie le nombre d'octets placés dans le tampon, si moins que les octets que vous essayiez d'envoyer, vous devez le gérer pour réessayer lors de la prochaine réception d'un événement FD_WRITE.

Vous ne pouvez pas vous assurer de la quantité de données déjà reçues par l'homologue à moins de vous tenir informé (mIRC DDC fait cela).

Je ne sais pas ce clearfyed vos doutes, espérons que cela a aidé :)

+0

Le problème est que je n'attends pas l'événement FD_WRITE, car pour cela je vais devoir envoyer suffisamment de données pour que le tampon interne soit plein et qu'il envoie à nouveau un événement FD_WRITE. Ce que je fais envoie de manière asynchrone, mais j'ai besoin de savoir que les données ont été envoyées avec succès. Comment je fais ça? – akif

+0

C'est simple, vous attendez le FD_WRITE :) – Havenard

+0

puisque j'envoie des messages courts (1, 2 octets) Je ne vais pas obtenir un autre événement FD_WRITE à moins que le tampon interne soit plein. – akif

0

Lorsque vous faites recv, vous devez enregistrer l'état de retour pour déterminer si les données ont été reçues. recv renvoie le nombre d'octets reçus et j'utiliserais l'indicateur MSG_WAITALL au lieu de zéro pour que le quatrième paramètre reçoive tout le message (en fonction de la taille de la mémoire tampon). Si le retour d'état est négatif, il y a eu une erreur de nature, telle que la connexion était proche de l'autre extrémité ou il y avait un autre problème. En ce qui concerne l'envoi, vous devez enregistrer la valeur de retour ainsi que l'état, mais dans ce cas, il n'y a pas de drapeau pour que toutes les données soient envoyées avant d'être renvoyées. Vous devrez déterminer le montant envoyé et ajuster le tampon et envoyer la taille en fonction de la valeur. Comme pour recv, une valeur négative indique qu'une erreur s'est produite.

Je voudrais lire les descriptions de fonction sur le site Web de Microsoft pour recv et send pour plus d'informations sur les valeurs de retour et les drapeaux.

+0

MSG_WAITALL est pour SOCK_DGRAM (UDP et RAW). SOCK_STREAM (TCP) se bloquerait. – Havenard

Questions connexes