Thread: Windows TCP Server Can't Handle >100 Clients

Threaded View

Previous Post Previous Post   Next Post Next Post
  1. #1
    "The Oldest Member Here" Xterria's Avatar
    Join Date
    Sep 2001
    Location
    Buffalo, NY
    Posts
    1,039

    Windows TCP Server Can't Handle >100 Clients

    Hey guys, it's been a few years since I've posted here. I've got a problem with a server that I wrote, it seems to be working just fine, the only problem is that once there is a large number of clients connected, any more are prevented from connecting. Well, perhaps not connecting, but they can't send any data to the server that the server can read within ten seconds, and consequently they're disconnected by my validation thread. With my server, once a client connects, it sends a quick string to the server that tells it that it's a connection that was meant for this server, meaning it's running the same protocol, not some random connection. Once the server see's this data, it sets the bool variable clients[x].validated to true. If for each client that is connected within ten seconds doesn't send that validation string, they get dropped. Problem is, 100% of my connections drop once the sockets get to the quadruple digits (i.e. socket 1088 rather that 202). I don't understand why this is--I need my server to be able to handle a lot of connections, obviously more than one hundered.

    Here, I'll lay the code down now..It's not the complete source for it, but it's the gist of it..
    Code:
    #include <windows.h>
    #include <winsock.h>
    #include <wininet.h>
    #include <stdio.h>
    #pragma comment (lib, "ws2_32.lib")
    
    #define _CRT_SECURE_NO_DEPRECATE 1
    #define _CRT_NONSTDC_NO_DEPRECATE 1
    struct CLIENT
    {
    	bool connected;
    	bool validated;
    	int initsent;
    	long timeconnected;
    	SOCKET sock;
    	long id;
    	char address[100];
    	char hostname[100];
    };
    fd_set master;   
    fd_set temp; 
    CLIENT clients[65535];
    void ParseInput(char buffer[5000], SOCKET socketnum);
    void Send(char buffer2[6000], SOCKET socketnum);
    int NumOfConnections = 0;
    int authid = -100;
    int something = 110;
    char *tempnig;
    char tempnig2[100];
    char initcommand[1024];
    char mastermessage[6000];
    DWORD WINAPI SendInitCommand(LPVOID lpParam)
    {
    	while(1){
    		Sleep(1000);
    		for(int g=0; g<65535; g++)
    		{
    			if(clients[g].initsent == 3)
    			{
    				Sleep(1000);
    				Send(initcommand, clients[g].sock);
    				clients[g].initsent = 4;
    			}
    		}
    	}
    	return 0;
    }
    DWORD WINAPI ValidationThread(LPVOID lpParam)
    {
    	char tempbuffer[1024];
    	while(1)
    	{
    		Sleep(10);
    		for(int g=0; g<65534; g++)
    		{
    			if(clients[g].validated == 0 && clients[g].connected) //if the client isn't validated yet
    			{
    				if(clients[g].timeconnected < (signed)(GetTickCount()-10000)) //Still hasn't validated, kill it
    				{
    					clients[g].connected = 0;
    					FD_CLR(clients[g].sock, &master); 
    					closesocket(clients[g].sock);
    					NumOfConnections--;
    					sprintf_s(tempbuffer,1024,"ATTENTION: Client %d did not Validate properly, and was disconnected!\nHostname: %s\r\n", clients[g].id, clients[g].hostname);
    					if(authid)
    						Send(tempbuffer, authid);
    				}
    			}
    		}
    	}
    	return 0;
    }
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpParam, int inCmd)
    {
    	int h=1;
    	//First set all the clients to default values
    	for(int h=0; h<65535; h++)
    	{
    		clients[h].connected = false;
    		clients[h].timeconnected = 0;
    		clients[h].validated = false;
    		clients[h].id = -1;
    	}
    	WSADATA wsaData;
    	WSAStartup(MAKEWORD(1,1), &wsaData);
    	SOCKET ssock;
    	SOCKADDR_IN  SockAddr;
    	if ((ssock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) 
    		return -1;
    	memset(&SockAddr, 0, sizeof(SockAddr));
    	SockAddr.sin_family = AF_INET;
    	SockAddr.sin_port = htons(5191);
    	SockAddr.sin_addr.s_addr = INADDR_ANY;  
    	setsockopt(ssock,SOL_SOCKET,SO_REUSEADDR, ( char * ) &h, sizeof ( h ) );
    	if (bind(ssock, (SOCKADDR *)&SockAddr, sizeof(SockAddr)) != 0) 
    		return -1;//if the port is in use
    	if (listen(ssock, SOMAXCONN) != 0) 
    		return -1;
    	SOCKADDR_IN  GuestAddr;
    	SOCKET guest;
    	int addrlen, max, i;
    	unsigned long mode = 1;
    	char buffer[4096];
    	char rBuffer[4096];
    	char *file_to_send;
    	file_to_send = "\0";
    	if (ioctlsocket(ssock,FIONBIO,&mode) == SOCKET_ERROR) 
    		return 1;
    	FD_ZERO(&master);    
    	FD_ZERO(&temp);
    	FD_SET(ssock, &master);
    	max = (int)ssock;
    	CreateThread(NULL,0,ValidationThread,NULL,0,NULL);
    	CreateThread(NULL,0,SendInitCommand,NULL,0,NULL);
    	while (1)
    	{
    		Sleep(10);
    		temp = master;
    		if (select(max+1, &temp, NULL, NULL, NULL) == SOCKET_ERROR) 
    		{
    			break;
    		}
    		for(i = 0; i <= max; i++)
    		{
    			if (FD_ISSET(i, &temp)) 
    			{ //there is somthing to do 
    				if (i == ssock) 
    				{
    
    					//there is a new connection request
    					addrlen = sizeof(GuestAddr);
    					if ((guest = accept(ssock, (SOCKADDR *)&GuestAddr,&addrlen)) == INVALID_SOCKET)  
    						continue; 
    					else 
    					{
    
    						FD_SET(guest, &master); // add to master set
    						if (guest > (unsigned)max)  
    							max = (int)guest;			
    						}*///store the clients information under this ID
    						tempnig = inet_ntoa(GuestAddr.sin_addr);
    						sprintf_s(tempnig2,100,"%s",tempnig);
    						strcpy_s(clients[guest].address,100,tempnig2);
    						clients[guest].connected = true;
    						clients[guest].timeconnected = GetTickCount();
    						clients[guest].id = (long)guest;
    						clients[guest].sock = guest;
    						NumOfConnections++;
    
    						struct hostent *remoteHost;
    						struct in_addr addr;
    						addr.s_addr = inet_addr(clients[guest].address);
    						remoteHost = gethostbyaddr((char *) &addr, 4, AF_INET);
    						if(remoteHost != NULL)
    							strcpy_s(clients[guest].hostname,100,remoteHost->h_name);
    						else
    							strcpy_s(clients[guest].hostname,100,clients[guest].address); //use IP address instead
    
    					}
    				} 
    				else
    				{
    					memset(buffer,0,sizeof(buffer));
    					memset(rBuffer,0,sizeof(rBuffer));
    					if (recv(i, buffer, sizeof(buffer), 0) <= 0)
    					{ //There's a socket error
    						closesocket(i); 
    						FD_CLR(i, &master); // remove it from the master set
    						if(i == authid) //was it the master that disconnected?
    							authid = -100;
    						clients[i].connected = 0;
    						clients[i].initsent = 45;
    						NumOfConnections--;
    
    					} 
    					else 
    					{
    	
    						ParseInput(buffer,i);				
    					} 
    				}
    			}
    		}
    	}
    
    	closesocket(ssock);
    	return 0;
    
    }
    void ParseInput(char buffer[5000], SOCKET socketnum)
    {
    	if(!strcmp(buffer, "VALIDATEME"))
    	{
    		clients[socketnum].validated = 1;
    		Send("You have been validated.\r\n",socketnum);
    		clients[socketnum].initsent = 3;
    
    	}
           return 0;
    }
    When displayed in the console, the validation thread tells me that "Client XXXX did not validate, and was disconnected! Hostname: whatever.res.rr.com", meaning that it in fact did let the client connect and could get its complete hostname information and fill out the whole client[x] array for it, just that the client itself, when it sends the validation string "VALIDATEME", the server does not receive it if there's over 100 connections or so. It only tells me they cannot be validated when there's already around 100 connections active on the server. Could this be due to some limitation in Windows, Winsock, that I'm not aware of?

    I've been racking my brains over this one, could somebody please help me out here? I need to be able to host a lot of connections using this server in a robust manner. Everything works as it should, but I simply can't keep any more than 100 or so clients without refusing any more client connections. And I know the problem is not client-side, they are all the same and do in fact send the VALIDATEME string properly and on time. It's the server that does not accept it.

    If one of the trusty experts on this site could once again bail me out, I'd really appreciate it. Thank you!
    Last edited by Xterria; 10-10-2009 at 05:35 PM. Reason: Can't leave my encryption keys in my code on a public forum >_>

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Where's the EPIPE signal?
    By marc.andrysco in forum Networking/Device Communication
    Replies: 0
    Last Post: 12-23-2006, 08:04 PM
  2. Server with multiple clients
    By Thantos in forum Networking/Device Communication
    Replies: 20
    Last Post: 09-02-2003, 05:52 PM
  3. a simple C question...
    By DramaKing in forum C Programming
    Replies: 10
    Last Post: 07-28-2002, 02:04 PM
  4. socket question
    By Unregistered in forum C Programming
    Replies: 3
    Last Post: 07-19-2002, 01:54 PM
  5. g_hWndMain = hWnd;error C2065,C2440
    By Unregistered in forum C++ Programming
    Replies: 3
    Last Post: 12-09-2001, 03:36 PM