Sign in to follow this  

send() returning WSAEWOULDBLOCK constantly after given time

This topic is 4199 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a system where during a frame information to send is collected into a buffer, and then sent all at once at the end of the frame. This works like a charm for several minuets, however after that all calls to send will return WSAEWOULDBLOCK. I am using win32 asynchronous sockets, and understand what the WSAEWOULDBLOCK means. I have a FD_WRITE handler that sends the data in the buffer if there is any. I have read that FD_WRITE will only be called if space has freed up in the network buffer that had previously been written to, and hence can be problematic for games. I have also read that this message is supposed to be sent following a send call that fails with WSAEWOULDBLOCK. It does not appear that this message is ever getting called. I tried disabling the message (during socket creation), doing so caused no noticeable change. Code: The sending code (called each frame):
…
game->network_stall = 0;
if( game->host )
{
	GameHost* ghost = (GameHost*) game;
	
	GamePlayer* player = ghost->players;
	while( player )
	{
		retry_counter = 0;
		while( !player->socket.Send() && retry_counter < 200 ) retry_counter++;
		
		if( retry_counter == 200 ) 
		{
			game->network_stall++;
			player->socket.FlushOutBuffer();
		}
		player = player->next;
	}
	if( game->network_stall >= game->num_players_accepted ) game->network_stall = 1;
	else													game->network_stall = 0;
}
else
{
	GameClient* gclient = (GameClient*) game;

	retry_counter = 0;
	while( !gclient->host_socket.Send() && retry_counter < 200 ) retry_counter++;
	if( retry_counter == 200 ) 
	{
		game->network_stall = 1;
		gclient->host_socket.FlushOutBuffer();
	}
	
}
…



The “.Send()” function used above:
//---------------------------------------------------------------
// Sends as much data from the out buffer as possible, returns	|
// 1 if all data was sent, otherwise returns 0			|
//---------------------------------------------------------------

int MessageQueue::Send()
{
	if( out_end_pos == out_start_pos )
	{
		out_end_pos = 0;
		out_start_pos = 0;

		return 1;
	}

	bytes_sent = send( sock, &(out_buffer[out_start_pos]), out_end_pos - out_start_pos, 0 );

	if( bytes_sent != SOCKET_ERROR ) {
		out_start_pos += bytes_sent;

//		sprintf( buffer, "[MessageQueue::Send()] Sent %i bytes", bytes_sent );
//		PRNT_ERROR( buffer );
	}
#ifdef NET_DEBUG
	else
	{
		bytes_sent = WSAGetLastError();
		sprintf( buffer, "[MessageQueue::Send()] Error: %i", bytes_sent );
		PRNT_ERROR( buffer );
	}
#endif

	if( out_end_pos == out_start_pos )
	{
		out_end_pos = 0;
		out_start_pos = 0;

		return 1;
	}
	else
	{
		return 0;
	}
}



My message handler:


//---------------------------------------------------------------
// Processes messages from winsock								|
//---------------------------------------------------------------

LRESULT OnNetworkMessage( WPARAM wparam, LPARAM lparam )
{
	int event, errmsg;

	event = WSAGETSELECTEVENT( lparam );
	errmsg = WSAGETSELECTERROR( lparam );


	switch( event ) {
	case FD_CONNECT:
		// The socket associated with this window has made a connect() attempt
		// and the results are back.
		if( errmsg != 0 ) 
		{
			sprintf( buffer, "[FD_CONNECT] ERROR: %i", errmsg );
			PRNT_ERROR( buffer );
		}
			
		if( !game->host )
		{
			GameClient* gclient = (GameClient*)game;

			// send request to join game
			gclient->host_socket.SendConnect( gclient->player_name, gclient->game_password );
		}
	
		break;
	case FD_READ:
		{
			// The first time this message is sent means the socket can be read from.
			// After that it means there is data to be read.  

			if( errmsg != 0 ) 
			{
				sprintf( buffer, "[FD_READ] ERROR: %i", errmsg );
				PRNT_ERROR( buffer );
				break;
			}
			
			if( game->host )
			{
				GameHost* ghost = (GameHost*)game;
				
				GamePlayer* player = ghost->GetPlayer( wparam );

				if( !player ) break;

				player->socket.Recieve();

			}
			else
			{
				GameClient* gclient = (GameClient*)game;

				gclient->host_socket.Recieve();
			}


		} break;
	case FD_WRITE:
		// The first time this message is sent means the socket can send data.
		// After that it means that the buffer of data to be sent now has room
		// to send some more.  Will probably not be called due to its strangeness
	
		if( errmsg != 0 ) 
		{
			sprintf( buffer, "[FD_WRITE] ERROR: %i", errmsg );
			PRNT_ERROR( buffer );
			break;
		}
		
			
		if( game->host )
		{
			GameHost* ghost = (GameHost*)game;
			
			GamePlayer* player = ghost->GetPlayer( wparam );

			if( !player ) break;

			player->socket.Send();

		}
		else
		{
			GameClient* gclient = (GameClient*)game;

			gclient->host_socket.Send();
		}

		break;
	case FD_CLOSE:
		{
			if( errmsg != 0 ) 
			{
				sprintf( buffer, "[FD_CLOSE] ERROR: %i", errmsg );
				PRNT_ERROR( buffer );
				break;
			}

			// The connection on the socket is being closed, either by the local
			// machine, the remote machine or because of loss of network.  
			if( game->host )
			{
				GameHost* ghost = (GameHost*)game;
				
				GamePlayer* player = ghost->GetPlayer( wparam );

				if( !player ) break;

				player->socket.Disconnect();
				ghost->DestroyPlayer( player );
				
				if( player->accepted ) game->num_players_accepted--;

			}
			else
			{
				GameClient* gclient = (GameClient*)game;

				gclient->host_socket.Disconnect();
			}

		} break;
	case FD_ACCEPT:
		{
			// accept connections, host only
			if( errmsg != 0 ) 
			{
				sprintf( buffer, "[FD_ACCEPT] ERROR: %i", errmsg );
				PRNT_ERROR( buffer );
				break;
			}

			if( !game->host )  break; // should never happen

			GameHost* ghost = (GameHost*) game;

			SOCKADDR_IN address;
			int         size = sizeof( SOCKADDR );

			SOCKET sock = accept( wparam, (LPSOCKADDR)&address, &size );

			if( sock != INVALID_SOCKET )
			{

				GamePlayer* player = ghost->CreatePlayer();

				// initialize
				player->socket.Set( sock );
				player->socket.type = NETCONNECT_TYPE_CLIENT;
				player->socket.connected = 1;
				
				player->ip_address = inet_ntoa( address.sin_addr );

				// the player is created, note however that he/she has yet to be accepted, however.
				player->accepted = 0;
			}

		} break;
	}
	return 0;
}



If anyone needs any more info don’t hesitate to ask. The only idea that has come to my mind is that I am running the network buffer out of space. However, I see no indication that recv is failing on the other end (the game remains synchronized up until the error starts to happen). Any help would be much appreciated, Thanks - Seth

Share this post


Link to post
Share on other sites
I am using WSAAsyncSelect, yes.

Relevent code:


int NetConnection::AsyncSetup( HWND window )
{
int ret;
if( type == NETCONNECT_TYPE_CLIENT )
{
if( !NetConnection::AsyncSetup( sock, window, FD_CONNECT | FD_CLOSE | FD_READ | FD_WRITE ) )
{
ret = WSAGetLastError();
sprintf( buffer, "[NetConnection::AsyncSetup] ERROR: WSAAsyncSelect( client ), error code: %i", ret);
PRNT_ERROR( buffer );

return NETWORK_ERROR;
}

return NETWORK_OK;
}

else if( type == NETCONNECT_TYPE_HOST )
{
if( !NetConnection::AsyncSetup( sock, window, FD_CONNECT | FD_CLOSE | FD_READ | FD_WRITE | FD_ACCEPT ) )
{
ret = WSAGetLastError();
sprintf( buffer, "[NetConnection::AsyncSetup] ERROR: WSAAsyncSelect( host ), error code: %i", ret);
PRNT_ERROR( buffer );

return NETWORK_ERROR;
}

return NETWORK_OK;
}

return NETWORK_ERROR;
}

...

int NetConnection::AsyncSetup( SOCKET s, HWND window, UINT messages )
{
ret = WSAAsyncSelect( s, window, SM_NETCONNECT_ASYNC, messages );

if( ret != SOCKET_ERROR ) return 1;

else
{
ret = WSAGetLastError();
sprintf( buffer, "[NetConnection::AsyncSetup(... )] Error: %i", ret );
PRNT_ERROR( buffer );

return 0;
}
}

Share this post


Link to post
Share on other sites
I assume you're using TCP.

Is the other end actually reading the data? Else the TCP window will fill up, and the stack won't be able to accept any more data until the other end has opened more window.

Even if the other end is receiving, but there's some limited bandwidth inbetween the server and client, you may fill up your window and not be able to push more data (because you're pushing more than the uplink will sustain).

Share this post


Link to post
Share on other sites
Thanks for the reply. I am using TCP, and I will run a test to ensure the data is getting across. If it was a bandwidth issue I would assume that after a time send would start working again. I have left it running for several minuets after the failure and it never corrects.

Edit:

Here are the relevant portions of the log files:
Client:
...
[MessageQueue::Recieve()] Recieved 200 bytes
[MessageQueue::Recieve()] Recieved 200 bytes
[MessageQueue::Recieve()] Recieved 200 bytes
[MessageQueue::Recieve()] Recieved 4096 bytes
[MessageQueue] Running low on in_buffer memory!
[MessageQueue] Out of in_buffer memory, stalling network communication!
[MessageQueue::LeaseData] invalid packet received (-90), flushing in_buffer
[MessageQueue::Send()] Error: 10035
[MessageQueue::Send()] Error: 10035
[MessageQueue::Send()] Error: 10035
...

Host:
...
[MessageQueue::Recieve()] Recieved 200 bytes
[MessageQueue::Recieve()] Recieved 1600 bytes
[MessageQueue::Recieve()] Recieved 200 bytes
[MessageQueue::Recieve()] Recieved 1600 bytes
[MessageQueue::Send()] Error: 10035
[MessageQueue::Send()] Error: 10035
[MessageQueue::Send()] Error: 10035
...

Which is incredibly interesting. It appears that I recieve to much info for my buffer, probably during a slowdown in framerate, which suspends receiving, which in turn suspends sending, and chaos resumes.

Thank you very much hplus0603, I should be able to figure it out from here.

[Edited by - CyberFox on June 14, 2006 7:35:43 PM]

Share this post


Link to post
Share on other sites

This topic is 4199 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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