![]() |
| | #1 |
| Intranasal Heroin User Join Date: Sep 2001 Location: Buffalo, NY
Posts: 1,033
| Windows TCP Server Can't Handle >100 Clients 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;
}
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 | |
| | #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 | |
| | #3 | |||
| Intranasal Heroin User Join Date: Sep 2001 Location: Buffalo, NY
Posts: 1,033
| Thank you for your response, cyberfish. Quote:
Quote:
Quote:
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 | |
| | #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:
Last edited by rags_to_riches; 10-11-2009 at 07:48 AM. | |
| rags_to_riches is offline | |
| | #5 |
| Intranasal Heroin User 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 | |
| | #7 |
| Intranasal Heroin User 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 | |
| | #8 |
| Intranasal Heroin User 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;
|
| Xterria is offline | |
| | #9 |
| Rampaging 35 Stone Welsh 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 | |
| | #10 |
| Intranasal Heroin User Join Date: Sep 2001 Location: Buffalo, NY
Posts: 1,033
| 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 | |
| | #11 |
| Rampaging 35 Stone Welsh 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 | |
| | #12 |
| Registered User Join Date: Sep 2004 Location: California
Posts: 2,845
| 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 | |
| | #13 | |
| Intranasal Heroin User Join Date: Sep 2001 Location: Buffalo, NY
Posts: 1,033
| Quote:
| |
| Xterria is offline | |
| | #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 | |
![]() |
| Thread Tools | |
| Display Modes | |
|
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 |