Sign in to follow this  
Ruffi

Probleme with WSAWaitForMultipleEvents

Recommended Posts

Ruffi    122
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 .

Share this post


Link to post
Share on other sites
hplus0603    11347
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.

Share this post


Link to post
Share on other sites
Ruffi    122
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]

Share this post


Link to post
Share on other sites
Sneftel    1788
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.

Share this post


Link to post
Share on other sites
Ruffi    122
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]

Share this post


Link to post
Share on other sites
Ruffi    122
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]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this