为什么大量Socket并发请求时会有部分失败?? 求高手解答!!

「已注销」 2013-04-03 01:54:18
现象:
同时启动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;
}


...全文
1353 7 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
zilaishuichina 2013-04-03
  • 打赏
  • 举报
回复
引用 5 楼 sherlinlove 的回复:
引用 4 楼 zilaishuichina 的回复:10048(Address already in use.): 目测是connect的频率太快,每一个socket在调用closesocket进行关闭操作后,虽然closesocket执行完毕,但是对应的占用端口并不是立即释放,这些端口需要继续处于占用状态,等待时间大约2ML(数据包最大生存周期),默认最大值为4分钟。……
2个数据包最大生存周期
赵4老师 2013-04-03
  • 打赏
  • 举报
回复
bool val=true; setsockopt(sk,SOL_SOCKET,((int)(SO_REUSEADDR)),(const char *)&val,4);
「已注销」 2013-04-03
  • 打赏
  • 举报
回复
引用 4 楼 zilaishuichina 的回复:
10048(Address already in use.): 目测是connect的频率太快,每一个socket在调用closesocket进行关闭操作后,虽然closesocket执行完毕,但是对应的占用端口并不是立即释放,这些端口需要继续处于占用状态,等待时间大约2ML(数据包最大生存周期),默认最大值为4分钟。用netstat命令查看端口状态,端口显示TIME_……
多谢回答,问题确实如你所说。 不过“等待时间大约2ML” 这个2ML是什么意思啊?
zilaishuichina 2013-04-03
  • 打赏
  • 举报
回复
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
「已注销」 2013-04-03
  • 打赏
  • 举报
回复
引用 2 楼 zhao4zhong1 的回复:
带宽不够?
应该不是, 首先是本地连接。其次不同的服务器程序出错比率不一样。 所以我感觉应该不是带宽的问题。
赵4老师 2013-04-03
  • 打赏
  • 举报
回复
带宽不够?
hanqingwu 2013-04-03
  • 打赏
  • 举报
回复
用wireshark抓包看一下,具体分析一下每个socket的握手过程,在哪一步失败了。

3,882

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 其它技术问题
社区管理员
  • 其它技术问题社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧