Skip to main content
GameDev.net gamedev.net
🔒 Locked

Problem starting/stopping server

Started by Vanz Feb 13, 2009 at 3:36 PM 3 replies 1.3k views
Original Post
Vanz
Vanz
I can start my server and have a client join and they can chat back and forth with data all day long, but when I shut down the server, I can't get the client to reconnect, it stalls out right here (part of server listener code below):

	// Any data on ListenerSock or data ready to read on any sockets
if (select(fdmax+1, &read_fds, NULL, NULL, &tv) == SOCKET_ERROR ) 
	Graphics.GDI_Text(10, g2->ScreenHeight-40, White, "Unable to Select!", fTimes); //x,y,c,Text


the server does not recognize any data coming in from the client trying to join the SECOND time... it all works good the first time but not after the server is canceled and re-initialized? fyi, most of my code is based on Beej's guide... Here's short version of starting server:

BOOL cApp::InitServer()
{
int 		error, yes=1; // for setsockopt() SO_REUSEADDR, below 
WSADATA		w;
int addr_size = sizeof (sockaddr);
//---------------------------------------------------------------------------------

FD_ZERO(&master); // clear the master and temp sets 
FD_ZERO(&read_fds); 
error = WSAStartup (0x0202,&w);
if (w.wVersion!=0x0202) // Wrong WinSock version!
	{	MessageBox(NULL, "Wrong WinSock version!", "Error Message", MB_OK);// cout << "Error:  Wrong WinSock version!\n";
		WSACleanup ();
		return FALSE;
	}

//if ( (ListenerSock = socket (AF_INET, SOCK_DGRAM,0)) == -1) // get the listener 
if ( (ListenerSock = socket (AF_INET, SOCK_STREAM,0)) == -1)
	{	MessageBox(NULL, "Can't get listener socket", "Error Message", MB_OK);
		WSACleanup ();
		return FALSE;
	}

ThisMachine.sin_family		= AF_INET;
ThisMachine.sin_port		= htons (Port1);
ThisMachine.sin_addr.s_addr = htonl (INADDR_ANY);

if (bind(ListenerSock,(LPSOCKADDR)&ThisMachine,sizeof(ThisMachine))==SOCKET_ERROR) //Unable to bind socket
	{	MessageBox(NULL, "Unable to bind socket!", "Error Message", MB_OK);// cout << "Error:  Wrong WinSock version!\n";
		WSACleanup ();
		CancelServer();
		return FALSE;
	}

if (setsockopt(ListenerSock, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(int)) == SOCKET_ERROR) 
	{	MessageBox(NULL, "Address already in use", "Error Message", MB_OK);//Error Message
		WSACleanup ();
		return FALSE;
	} 

if (listen(ListenerSock, 1)==SOCKET_ERROR) //Unable to listen, 20
	{	MessageBox(NULL, "Unable to listen!", "Error Message", MB_OK);//Error Message
		WSACleanup ();
		return FALSE;
	}

FD_SET(ListenerSock, &master); // add the listener to the master set 
fdmax = ListenerSock; // so far, it's this one 
fdmin = fdmax-1;

return TRUE;
} // End cApp::InitServer


short version of cancelling server:

BOOL cApp::CancelServer()
{
closesocket(ListenerSock);
FD_ZERO(&master); // clear the master and temp sets 
FD_ZERO(&read_fds);
fdmax=1;
fdmin=50000;
return TRUE;
} // End cApp::CancelServer


short version of server listening:

BOOL cApp::ServerListen() // Server to deect new sockets and receive network data
{
unsigned int		i, nbytes;
int			j, addr_size = sizeof (sockaddr);
char 			buf[1]; 	// buffer for client data 
struct			timeval	tv; // Timeout time for select()
bool			ReceivedGoodData, AllHumanPlayers;
//---------------------------------------------------------------------------------

tv.tv_sec = 0; tv.tv_usec = 5; // Set Timeout time tv_usec = 500000 = 0.5s
read_fds = master; // copy master

	// Any data on ListenerSock or data ready to read on any sockets
if (select(fdmax+1, &read_fds, NULL, NULL, &tv) == SOCKET_ERROR ) 
	Graphics.GDI_Text(10, g2->ScreenHeight-40, White, "Unable to Select!", fTimes); //x,y,c,Text
	
	// run through the existing connections looking for data to read 
for(i = fdmin; i <= fdmax; i++) 
	{ 
	if (FD_ISSET(i, &read_fds)) // we got one!!
		{ 
		Graphics.GDI_Text(10, g2->ScreenHeight-40, Yellow, "Activity Detected!", fTimes); //x,y,c,Text
		//Graphics.GDI_EndFlip(*g2);

		if (i == ListenerSock) 
			{
	
			if ((newfd = accept (ListenerSock, &ExternalMachine, &addr_size))== -1) 
				{	MessageBox(NULL, "Unable to Accept!", "Error Message", MB_OK);//Error Message
					WSACleanup ();
					return FALSE;
				} // End if accept
				else
				{

				buf[0] = (char)ConnectOkayID;// Send connection okay notice
				send (newfd,buf,1,0);
				FD_SET(newfd, &master);		// add new Player to master set 
				if (newfd > fdmax)			// keep track of the maximum 
					fdmax = newfd;
	
				if (newfd < fdmin)			// keep track of the maximum 
					fdmin = newfd;


				} // End else

			} // End (i == listener)
			else
			{
				// handle data from a client from something OTHER than ListenerSock1
			nbytes = recv(i, buf, 1, 0);
			if (nbytes <= 0) 
				{ 
					// got error or connection closed by client 
				if (nbytes == 0) 
					{	// connection closed 
					//MessageBox(NULL, "Socket Hung", "Error Message", MB_OK);
					DeleteClientPlayer(i, FALSE); // socket#, ServerBootingClient
					}
					else 
					{ 
					MessageBox(NULL, "Receive Error", "Error Message", MB_OK);
					} 
				} // End if nbytes
				else
				{	// ------ We got some data from a client  ---------------


					// Figure out what Class is being sent from a Client

				if (buf[0]==(char)ClientBroad1) // Okay got Broadcast message now send back server name
					{
					SendClass(ClientBroad1, 0, Client, ListenerSock2); //ClassID, cIndex, SendTo, SocketID
					ReceivedGoodData=TRUE;
					} // note this is sending not receiving



				} // end if (nbytes <= 0) 
			}// End else
		} // (FD_ISSET(i, &read_fds))
	} // End for i


return TRUE;
} // End cApp::ServerListen



So it would appear I am not cancelling or shutting something down properly... any help or even ideas would be appreciated... Thanks, rh
hplus0603
hplus0603
Are you using SO_REUSEADDR?
Else, does the problem go away if you wait 5 minutes before re-starting the server?
enum Bool { True, False, FileNotFound };
Vanz
Vanz
So in the middle of my init server code above I use SO_REUSEADDR here:

if (setsockopt(ListenerSock, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(int)) == SOCKET_ERROR) 	{	MessageBox(NULL, "Address already in use", "Error Message", MB_OK);//Error Message		WSACleanup ();		return FALSE;	} 


Am I not using it correctly?

No, it does not clear up after 5mins?

Thanks for the suggestiton hplus0603, I'm not sure at this point how to even debug this further, is there away to be sure that a socket is completely closed? When I recall my BOOL cApp::InitServer() function there are no errors, it appear to initialize properly, yet it just does not select or grab the data sent from the client... I'm sure the client is sending the data because if I leave the client alone, then exit the server, restart it, everything works fine again...

rh
hplus0603
hplus0603
For SO_REUSEADDR to work, you need to set it before you attempt to bind.

However, if the bind succeeds, then that's not the problem.

Use the debugger to trace through the server, and use Wireshark or similar to capture network data when trying to connect from another machine.
enum Bool { True, False, FileNotFound };
aissp
aissp
hm, actually, the problem is unclear for me. So, let me step-by-step explain, how i will work around this problem.
(1) just after your server stopped run netstat -a to verify sockets in TIME-WAIT state
(2) Check your client - I guess the connect function on client side after server restarting should return timeout error.
(3) Set up sniffer on server (it may be ethereal or it clone, or netpeeker trial version) and figure out what's happening with connection handshake when your server "stall", so if server adress is x.x.x.x:xx and client adress is yyy.yyy.yyy.yyy on the sniffer you will see something like:
yyy->xxx SYN
xxx->yyy SYN+ACK
yyy->xxx ACK
yyy->xxx RST
the las string means that your listening socket should get readable and select must return...

Well, i totally agree with hplus0603 the right sequence of function should be setsockopt(), bind().

And one little question:

BOOL cApp::CancelServer()
{
closesocket(ListenerSock);
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
fdmax=1;
fdmin=50000;
return TRUE;
}

Do you close other sockets here or not?

Good luck :)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.