读书人

为何大量Socket并发请求时会有部分失败

发布时间: 2013-04-21 21:18:07 作者: rapoo

为什么大量Socket并发请求时会有部分失败?? 求高手解答!!
现象:
同时启动2000个线程,每个线程都去访问同一个服务器(IP、端口相同)。
发现会有部分线程连接失败,错误码一般有下面两个:
①10048(Address already in use.)
②10061(Connection refused.)

另:不同的服务器出错的比率也不同,自己写的Java服务端出错的比率要比Apache的多(服务端只把客户端发来的字符串打印到屏幕上,然后继续接收下一个请求)。

问题:
为什么在很短的时间内有过多的网络连接请求时,会有部分连接失败?其根本原因是什么?(1024-5000内的端口还有剩余)
Java/C/C++、Windows/Linux都有同样的问题,所以应该是Socket或底层网络设备或驱动的问题,不过没找到权威的资料。

如能给几个参考文档也是极好的~

注:请不要回答如何规避这个问题的方法,公司要我调查出现这个问题的原因。调查好久了没找到答案、只好发帖求助了。

代码:
下面是客户端代码,服务端的很简单就不贴出来了,访问www.baidu.com 或本地Apache服务都是一样的问题。


// main 函数
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
// Win Socket初始化
// ...

// 创建2000个线程
HANDLE ths[2000] = {0};
for(int i=0; i<2000; i++) {
HANDLE hTh = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc,
(LPVOID)(i+1), CREATE_SUSPENDED, NULL);
if(NULL == hTh) {
printf("Create thread failed(%d:%d)\n", i, GetLastError());
return -1;
}
ths[i] = hTh;
}
printf("Create thread success.\n");

// 启动创建好的线程
for(int i=0; i<2000; i++) {
ResumeThread(g_th[i]);
}

Sleep(5000);
return nRetCode;
}


// 线程函数
DWORD ThreadProc(LPVOID lpParameter)
{
char ch[100] = {0};
int i = (int)lpParameter;

SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);
if (INVALID_SOCKET == sockClient) {
printf("socket error(%d:%d)\n", i, WSAGetLastError());
return 1;
}

SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr("localhost");
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(80);
int err = connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
if(SOCKET_ERROR == err) {
// 会出现10048、10061两种类型的错误
printf("connect error(%d:%d)\n", i, WSAGetLastError());
return 1;
}

sprintf(ch, "GET /app/?a=%d HTTP/1.1", i);
err = send(sockClient, ch, strlen(ch)+1, 0);
if(SOCKET_ERROR == err) {
printf("send error(%d:%d)\n", i, WSAGetLastError());


return 1;
}
closesocket(sockClient);

printf("proc ok(%d)\n", i);
return 0;
}


socket 服务器
[解决办法]
10048(Address already in use.):
目测是connect的频率太快,每一个socket在调用closesocket进行关闭操作后,虽然closesocket执行完毕,但是对应的占用端口并不是立即释放,这些端口需要继续处于占用状态,等待时间大约2ML(数据包最大生存周期),默认最大值为4分钟。用netstat命令查看端口状态,端口显示TIME_WAIT,在4分钟内如果对同一个端口进行connect,就会10048。

10061(Connection refused.):
目测是connect的频率太快,服务器拒绝了该连接,服务器的listen(SOCKET s, int backlog),
backlog就是等待连接队列的最大长度。比如服务器设置的是10,你同时有11个客户端连接请求,那么最后一个连接就会10061

读书人网 >C++

热点推荐