Advertisement

Probleme with WSAWaitForMultipleEvents

Started by December 04, 2005 01:30 PM
4 comments, last by Ruffi 19 years, 2 months ago
Hi :) I would like to know if WSAWaitForMultipleEvents just wait for new event or also use a queue for all unread event. I say that because when I send two message to a client in a short laps of time, if the managing of the first one is not finish before receiving the second, the next call to WSAWaitForMultipleEvents not give the second message .
If you're using TCP, chances are that you get signaled for both messages together (because of TCP packet coalescing). Look in the Forum FAQ for how to packetize separate messages over TCP. You also need to read all you can out of the socket each time the event is signalled, to make sure you don't leave something there and then block forever.
enum Bool { True, False, FileNotFound };
Advertisement
Thanks for the reply :)

Yes, I am using TCP
I have seen that your advise is to send the lenght of the message before sending it (because it can be split or be fusioned with another).
Acutaly, I use getsockopt for getting the size of the buffer : Bad idea ?

[edit] You're all right, I received all message in the same time [/edit]

So, instead of that :

[sender]
send( socket, (char*)data, bufferSize, 0 );

[receiver]
DWORD bufferSize;
int dwordSize = sizeof(bufferSize)
char* buffer;
char* data;

getsockopt( connection->m_socket, SOL_SOCKET, SO_RCVBUF, (char*)&(bufferSize), &dwordSize );
buffer = new char[bufferSize];
bufferSize = recv( connection->m_socket, buffer, bufferSize, 0);
data = new char[bufferSize];
memcpy( data, buffer, bufferSize);


I will have something like that :

[sender]
send( socket, htons( (u_short)bufferSize ), sizeof(u_short), 0 );
send( socket, (char*)data, bufferSize, 0 );

[receiver]
char* buffer;
u_short bufferSize;
int bufferSizeInt;
int byteRcved=0;

recv( connection->m_socket, bufferSize, sizeof(u_short), 0);
bufferSizeInt = (int)htons(bufferSize);
buffer = new char[bufferSizeInt];

while( byteRcved < bufferSizeInt )
{
byteRcved += recv( connection->m_socket, buffer+byteRcved , bufferSizeInt-byteRcved , 0)
}
data = new char[bufferSizeInt ];
memcpy( data, buffer, bufferSize)



But I don't understand how to read all I can from the socket.
With this algorithme, I only will receive the first message. I can't try to receive another size indicator, because if it is the last message, this will block the thread for other messages



-----------------------------------------------------------------

(here is my actual code)
void WINAPI cConnection::getMessages( cConnection* connection ){   HANDLE eventsArray[2];   bool stopThread = false;   DWORD result;   WSANETWORKEVENTS info;   while( !stopThread )   {      eventsArray[0] = connection->m_hStopThread;      eventsArray[1] = connection->m_event;            // wait for an event      result = WSAWaitForMultipleEvents( 2, eventsArray, FALSE, WSA_INFINITE, FALSE );      switch(result)      {         // m_hStopThread -> we finish the thread         case WSA_WAIT_EVENT_0 :            stopThread = true;         break;         // message from the server         case WSA_WAIT_EVENT_0+1 :            // get information about this event            WSAEnumNetworkEvents( connection->m_socket, connection->m_event, &info );                     switch(info.lNetworkEvents)         {            // server connection closed            case FD_CLOSE:               // server close !               WaitForSingleObject( connection->m_hMutex, INFINITE );                  connection->m_connected = false;               ReleaseMutex( connection->m_hMutex );            break;            case FD_READ:               char* buffer;               void* data;               DWORD bufferSize;               int dwordSize = sizeof(bufferSize);               // get the size of the buffer               getsockopt( connection->m_socket, SOL_SOCKET, SO_RCVBUF, (char*)&(bufferSize), &dwordSize );               buffer = new char[bufferSize];               if( (bufferSize = recv( connection->m_socket, buffer, bufferSize, 0)) == SOCKET_ERROR )                  break; // TODO -> managing the error               // copy the data               data = new char[bufferSize];               memcpy( data, buffer, bufferSize);               delete [] buffer;               WaitForSingleObject( connection->m_hMutex, INFINITE );                  connection->processMessage( data, bufferSize );               ReleaseMutex( connection->m_hMutex );               delete [] data;                           break;         } // switch(info.lNetworkEvents)         break; // case WSA_WAIT_EVENT_0+1      } // switch(result)   } // while( !stopThread )}


bool cServer::sendData( SOCKET socket, void* data, int bufferSize ){   if( send( socket, (char*)data, bufferSize, 0 ) == SOCKET_ERROR )      return false;   return true; }


[Edited by - Ruffi on December 5, 2005 10:51:37 PM]
Quote:
Original post by Ruffi
But I don't understand how to read all I can from the socket.
With this algorithme, I only will receive the first message. I can't try to receive another size indicator, because if it is the last message, this will block the thread for other messages

Use a stateful receive buffer, and decouple message receiving from message processing. Like so:

On message m received from client c:    While m is not empty:        If an incomplete packet p, from client c is in progress:            fill p with data taken from c, but no more than needed to complete p            If p is complete:                pass p off to processing layer                mark client c as not having a packet in progress        Else:            read length of packet using data taken from c            start incomplete (empty) packet p for client c

Basically, you keep around fragments until they're complete, and then you process them.
Hi tried to do like you said.

But I have a probleme : I send the size of the message and I send its data, by two differents call of send(). The first succed, but the second failed (return SOCKET_ERROR )
In the reception, the first call of recv(), to get the lenght of the message, fail (return -1).

This is how I send the message (server side)
bool cServer::sendData( SOCKET socket, void* data, int bufferSize ){	u_short size = htons( (u_short)bufferSize );	if( send( socket, (char*)&size, sizeof(u_short), 0 ) == SOCKET_ERROR )		return false;	if( send( socket, (char*)data, bufferSize, 0 ) == SOCKET_ERROR )// it fail here		return false; 	return true; }


This is how I receive the message (client side)
case FD_READ:{	DWORD messageSize;	int dwordSize = sizeof(messageSize);	u_short bufferSizeTmp = 0;	int messageRead = 0;	int byteToReceive;	char* buffer;	int byteRcved;	// get the size of all messages	getsockopt( connection->m_socket, SOL_SOCKET, SO_RCVBUF, (char*)&(messageSize), &dwordSize );	// while all hasn't been all read	while( messageRead < (int)messageSize )	{		// get the size of the message		messageRead += recv( connection->m_socket, (char*)bufferSizeTmp, sizeof(u_short), 0);// failed here : messageRead = -1, bufferSizeTmp = 0		byteToReceive = (int)ntohs(bufferSizeTmp);		buffer = new char[ byteToReceive ];		byteRcved = 0;				// get the message		while( byteRcved < byteToReceive )		{			int size = recv( connection->m_socket, buffer+byteRcved , byteToReceive-byteRcved , 0);			if( size > 0)			{				messageRead += size;				byteRcved += size;			}		}		// process the message		WaitForSingleObject( connection->m_hMutex, INFINITE );			connection->processMessage( buffer, byteToReceive );		ReleaseMutex( connection->m_hMutex );		delete [] buffer;	}}


[Edited by - Ruffi on December 5, 2005 11:54:34 PM]
It works :)
Not very well, but I will try to fix them.

Thanks you very much ^_^

[Edited by - Ruffi on December 6, 2005 12:08:44 AM]

This topic is closed to new replies.

Advertisement