C Board  

Go Back   C Board > General Programming Boards > Networking/Device Communication

Reply
 
LinkBack Thread Tools Display Modes
Old 10-10-2009, 05:18 PM   #1
Intranasal Heroin User
 
Xterria's Avatar
 
Join Date: Sep 2001
Location: Buffalo, NY
Posts: 1,033
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 >_>
Xterria is offline   Reply With Quote
Old 10-11-2009, 01:00 AM   #2
Registered User
 
Join Date: Dec 2006
Posts: 1,780
Are you sure the problem is in your code?

Delays are to be expected when you are handling this many concurrent connections. Are you sure your hardware (especially router if you are using one, they drop connections when they run out of memory, and low end models have little memory) is good enough?

Where are the clients connecting from?
cyberfish is online now   Reply With Quote
Old 10-11-2009, 04:13 AM   #3
Intranasal Heroin User
 
Xterria's Avatar
 
Join Date: Sep 2001
Location: Buffalo, NY
Posts: 1,033
Thank you for your response, cyberfish.

Quote:
Are you sure the problem is in your code?
I really wish the problem wasn't with my code. But you may be correct on that, since I have no idea what the problem could be.
Quote:
Where are the clients connecting from?
The connections themselves obviously come from external addresses. When about 100 or so connect, the validation thread begins to drop 100% of all new connections.
Quote:
Delays are to be expected when you are handling this many concurrent connections. Are you sure your hardware (especially router if you are using one, they drop connections when they run out of memory, and low end models have little memory) is good enough?
To rule out the possibility that this could be due to routers/switches/etc, I ran the server on my own WinXP machine. The server does not take up that much memory unless bogged down with a million connections. I then ran the client program(the client that sends the VALIDATEME string) 50 times over. So far so good, 50 connections are currently on the server and responding properly. I run client.exe another 30 times. Things are still alright. I run it a few dozen more times, and boom, instead of them connecting, they drop due to lack of validation. Every single one of them past ~100 clients or so. And remember, the same thing happens when external IP's connect rather than >100 localhost clients, so you can rule out the memory running out due to too many client.exe's running at the same time--because 100 unique connections from different machines all over the country provide the same results--dropping after the socket numbers go quadruple digit.

Please, somebody solve this, I've researched this to no end. I would really appreciate any input anybody would have. Thank you all again.
Xterria is offline   Reply With Quote
Old 10-11-2009, 07:44 AM   #4
and the Hat of Ass
 
Join Date: Dec 2007
Posts: 730
Not enough backlog perhaps? See Winsock Programmer's FAQ: Advanced Winsock Issues, section 4.14.

EDIT: Nah, bad answer. Maybe you need to rethink your I/O strategy? See http://tangentsoft.net/wskfaq/articl...rategies.html:
Quote:
If your server only has to support a moderate number of connections — up to 100 or so — you may not need overlapped I/O. Overlapped I/O is not easy to program, so if you don't need its efficiencies, you can save yourself a lot of trouble by using a simpler I/O strategy.

Last edited by rags_to_riches; 10-11-2009 at 07:48 AM.
rags_to_riches is offline   Reply With Quote
Old 10-11-2009, 05:09 PM   #5
Intranasal Heroin User
 
Xterria's Avatar
 
Join Date: Sep 2001
Location: Buffalo, NY
Posts: 1,033
Thanks for that link rags_to_riches, but I'm not sure I can do much with it, considering the fact that when I googled "Overlapped I/O Server Windows TCP C++" in google....this thread that I just created was the first result. I find this very ironic and agitating at the same time. Honestly, is this not common knowledge to program servers that need to support a large number of clients?

Could somebody please at least point me in a direction where I can somehow figure this out? I need some of you experts to throw me a bone or two, I'm still not getting very far. Thanks!
Xterria is offline   Reply With Quote
Old 10-11-2009, 08:27 PM   #6
and the Hat of Ass
 
Join Date: Dec 2007
Posts: 730
Well, searching MSDN I found this, which might be helpful.
rags_to_riches is offline   Reply With Quote
Old 10-12-2009, 10:29 AM   #7
Intranasal Heroin User
 
Xterria's Avatar
 
Join Date: Sep 2001
Location: Buffalo, NY
Posts: 1,033
Thank you rags_to_riches, that makes all the difference. I've been coding my servers like this for a long time and haven't run into this problem before, I've actually been able to simultaneously hold over 1500 connections in the past using code similar to what I posted, and I would link the servers together to have a large protocol running. From here on in I'll be using Overlapped I/O.

Last edited by Xterria; 10-12-2009 at 10:32 AM.
Xterria is offline   Reply With Quote
Old 11-01-2009, 04:14 AM   #8
Intranasal Heroin User
 
Xterria's Avatar
 
Join Date: Sep 2001
Location: Buffalo, NY
Posts: 1,033
Okay, sorry to bump this thread, but just in case people run into the same problem I do with this, Overlapped I/O has *absolutely nothing* to do with what was going wrong.

See winsock.h:
Code:
typedef UINT_PTR        SOCKET;

/*
 * Select uses arrays of SOCKETs.  These macros manipulate such
 * arrays.  FD_SETSIZE may be defined by the user before including
 * this file, but the default here should be >= 64.
 *
 * CAVEAT IMPLEMENTOR and USER: THESE MACROS AND TYPES MUST BE
 * INCLUDED IN WINSOCK.H EXACTLY AS SHOWN HERE.
 */
#ifndef FD_SETSIZE
#define FD_SETSIZE      64
#endif /* FD_SETSIZE */

typedef struct fd_set {
        u_int   fd_count;               /* how many are SET? */
        SOCKET  fd_array[FD_SETSIZE];   /* an array of SOCKETs */
} fd_set;
And there you go. I had this problem years ago with my servers like this and I simply forgot this one, simple, stupid rule--FD_SETSIZE limits the amount of file descriptors you can use on any server. This has nothing to do with the I/O, it's simply because the number of file descriptors was capped to 64 by default by winsock.h. All you have to do is #define FD_SETSIZE to a multiple of 1024 and you're all set. I can't believe I missed this.
Xterria is offline   Reply With Quote
Old 11-01-2009, 09:20 AM   #9
Rampaging 35 Stone Welsh
 
abachler's Avatar
 
Join Date: Apr 2007
Posts: 2,924
Thread per connection runs into problems with more than about 16 connections, as you are finding out. Use a connection pool.
abachler is offline   Reply With Quote
Old 11-01-2009, 05:20 PM   #10
Intranasal Heroin User
 
Xterria's Avatar
 
Join Date: Sep 2001
Location: Buffalo, NY
Posts: 1,033
Quote:
Originally Posted by abachler View Post
Thread per connection runs into problems with more than about 16 connections, as you are finding out. Use a connection pool.
What does "thread per connection" have to do with anything? I'm not creating a new thread for every connection, you really need to take a look at the code. I'm able to handle up to 65535 connections now, tested it over a few machines and gotten into the tens of thousands, which is more than I need.

Last edited by Xterria; 11-02-2009 at 02:42 AM.
Xterria is offline   Reply With Quote
Old 11-02-2009, 02:50 PM   #11
Rampaging 35 Stone Welsh
 
abachler's Avatar
 
Join Date: Apr 2007
Posts: 2,924
Perhaps you could point out the parts of your code you are having issues with, or do you expect me to read through the 90% that are irrelevant to the problem?
abachler is offline   Reply With Quote
Old 11-02-2009, 03:23 PM   #12
Registered User
 
Join Date: Sep 2004
Location: California
Posts: 2,845
Quote:
Originally Posted by abachler View Post
Perhaps you could point out the parts of your code you are having issues with, or do you expect me to read through the 90% that are irrelevant to the problem?
What problem? He posted to say that he fixed the problem he was having, and gave the solution in case others came across this thread down the road.
__________________
bit∙hub [bit-huhb] n. A source and destination for information.
bithub is offline   Reply With Quote
Old 11-02-2009, 06:33 PM   #13
Intranasal Heroin User
 
Xterria's Avatar
 
Join Date: Sep 2001
Location: Buffalo, NY
Posts: 1,033
Quote:
What problem? He posted to say that he fixed the problem he was having, and gave the solution in case others came across this thread down the road.
Exactly. abachler, you seriously need to read through the thread before replying. I'm seeing you post prematurely all over this board.
Xterria is offline   Reply With Quote
Old 11-02-2009, 07:21 PM   #14
and the Hat of Ass
 
Join Date: Dec 2007
Posts: 730
I try to think about that time I ran over the mailman to prevent that from happening.
rags_to_riches is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump

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


All times are GMT -6. The time now is 11:04 PM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.0 RC2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22