I have a game server in C++ and I'm using a network library that uses winsock in Windows. I've been stress-testing my server to see how many connections it can accept at a time. It works fine when I connect using my game clients but my game clients can no longer connect after I do a stress-test described below.
The stress test is, I connected to my server about 1000 times using a simple program for loop that just starts a tcp connection with my game server and closes it right away. They all connect. Then, after, I try to connect with my game. The game does not connect at all.
I checked the tcpaccept() function from the library (see below), no output. For some reason, accept() stops accepting connections after my "attack" of 1000 connections. What could possibly make my server just stop accepting connections?
Here's my summary of my loop that listens and accepts connections and closes them:
bool serverIsOn = true;
double listen = tcplisten(12345, 30000, 1);
setnagle(listen, true);
...
while(serverIsOn){
double playerSocket = tcpaccept(listen, 1);
if(playerSocket > -1){
cout << "Got a new connection, socket ID: " << playerSocket << endl;
//add their sockID to list here!
addSockIDToList(playerSocket);
}
//Loop through list of socks and parse their messages here..
//If their message size == 0, we close their socket via closesocket(sockID);
loopThroughSocketIdsAndCloseOnLeave();
}
cout << "Finished!" << endl;
Here's the definitions for tcplisten, tcpaccept, CSocket::CSocket(SOCKET), CSocket::tcplisten(...) and CSocket::tcpaccept(...):
double tcplisten(int port, int max, int mode)
{
CSocket* sock = new CSocket();
if(sock->tcplisten(port, max, mode))
return AddSocket(sock);
delete sock;
return -1;
}
double tcpaccept(int sockid, int mode)
{
CSocket*sock = (CSocket*)sockets.item(sockid);
if(sock == NULL)return -1;
CSocket*sock2 = sock->tcpaccept(mode);
if(sock2 != NULL)return AddSocket(sock2);
return -1;
}
...
CSocket::CSocket(SOCKET sock)
{
sockid = sock;
udp = false;
format = 0;
}
bool CSocket::tcplisten(int port, int max, int mode)
{
if((sockid = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) return false;
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if(mode)setsync(1);
if(bind(sockid, (LPSOCKADDR)&addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
{
closesocket(sockid);
return false;
}
if(listen(sockid, max) == SOCKET_ERROR)
{
closesocket(sockid);
sockid = INVALID_SOCKET;
return false;
}
return true;
}
CSocket* CSocket::tcpaccept(int mode)
{
if(sockid == INVALID_SOCKET) return NULL;
SOCKET sock2;
if((sock2 = accept(sockid, (SOCKADDR *)&SenderAddr, &SenderAddrSize)) != INVALID_SOCKET)
{
//This does NOT get output after that 1000-'attack' test.
std::cout << "Accepted new connection!" << std::endl;
CSocket*sockit = new CSocket(sock2);
if(mode >=1)sockit->setsync(1);
return sockit;
}
return NULL;
}
What can I do to figure out why accept() no longer accepts connections after my 1000-connection stress test? Does it have something to do with the way I close connections after their finished? When I do that, all I do is just call: closesocket(sockID).
Please ask for any other code needed!
EDIT: I just noticed that my "stress-test" java program is getting an exception after its connected around 668 times. Here's the exception:
Exception in thread "main" java.net.ConnectException: Connection refused: connect at java.net.DualStackPlainSocketImpl.connect0(Native Method) at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:579) at java.net.Socket.connect(Socket.java:528) at java.net.Socket.<init>(Socket.java:425) at java.net.Socket.<init>(Socket.java:208) at sockettest.SocketTest.main(SocketTest.java:63) Java Result: 1
INVALID_SOCKET) after closing the socket, then later they act on the not-invalid socket handle and end up acting on a completely different socket that happened to be using the same handle value. That is why you should ALWAYS invalidate a handle after you close it. - Remy Lebeauconnect()can fail with a "connection refused" error for several different reasons, but the most common (assuming a firewall is not blocking the connection) is that either the server socket is not listening on the port, or the server socket's backlog of pending connections is full (which would imply thataccept()is not being called often enough, if at all). - Remy LebeauINVALID_SOCKET), eg:closesocket(sockid); sockid = INVALID_SOCKET;You are doing that inCSocket::tcplisten()whenlisten()fails, but not whenbind()fails. - Remy Lebeau