我在C++中有一个游戏服务器,我正在使用一个网络库,它在Windows中使用winsock。我一直在压力测试我的服务器,看看它一次能接受多少连接。当我使用我的游戏客户端连接时,它工作得很好,但是在我做了下面描述的压力测试之后,我的游戏客户端就不能再连接了。
压力测试是,我使用一个简单的程序for循环连接到我的服务器大约1000次,它只是启动与我的游戏服务器的tcp连接,并立即关闭它。它们都连接在一起。然后,之后,我试着连接我的游戏。这个游戏根本不相连。
我检查了库(参见下面的)的tcpaccept()函数,没有输出。由于某种原因,accept()在我对1000个连接的“攻击”之后停止接受连接。什么能让我的服务器停止接受连接呢?
下面是我的循环总结,它侦听并接受连接并关闭它们:
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;
以下是tcplisten、tcpaccept、CSocket::CSocket(套接字)、CSocket::tcplisten(.)的定义和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;
}
在我的1000连接压力测试之后,我能做些什么来找出为什么accept()不再接受连接?这与我在他们结束后关闭联系的方式有关吗?当我这么做的时候,我所做的就是打电话:closesocket(sockID).
请询问所需的任何其他代码!
编辑:-我刚刚注意到我的“压力测试”java程序在668倍连接后出现异常。这是一个例外:
线程"main“中的异常( java.net.ConnectException: Connection拒绝:Connection at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79),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.(Socket.java:425) at java.net.Socket.(Socket.java:208) at Socket.java:528
发布于 2015-05-23 12:52:55
因为您的服务器端正在关闭套接字,所以它们很可能在time_wait中停留几分钟。Windows具有控制最大套接字和各种状态的各种参数。我猜您的程序在几分钟后再次开始工作,并且可能会在事件查看器中出现一些警告。
另一种选择可能是忽略这些套接字几分钟,并希望它们消失。当您完全没有响应时,客户端会调用closesocket,这意味着您不会招致time_wait。这通常是可行的,但并非总是如此。如果没有,则在后台缓慢地调用closesocket()。
如果您真的想要,您可以重置连接,详细信息请参阅LINGER (zero) - when it's required,但是重新设置连接是不正常的,所以一定要广泛阅读关于So_linger和teardown是如何工作的。
发布于 2015-05-23 14:40:34
事实证明,这个库有自己的关闭套接字的方法:
int closesock(int sockid)
{
CSocket*sock = (CSocket*)sockets.item(sockid);
if(sock == NULL)return -1;
delete sock;
sockets.set((int)sockid, NULL);
return 1;
}
因此,它通过套接字列表中的sockID获取当前套接字。然后,如果sockID与有效的套接字相关,则删除sock对象并在套接字列表中将其设置为NULL。
问题是,我只是调用closesocket(sockID)而不是closesock(sockID),后者执行了关闭套接字所需的必要操作。
谢谢大家的帮助。
https://stackoverflow.com/questions/30417144
复制