网络socket sokcet并行连接最大连接数限制的问题

jakky520 2009-09-16 10:14:05
现在做模拟网络客户端和服务器端的时候遇到一个问题, 在window系统下测试sokcet并行最大连接数的问题,发现当socket连接数达到3700-4000的时候sokcet就connect不上了,打出错误链接 提示10055错误 ,是由于底层缓存不够导致 , 这个问题瓶颈在哪里一直没找到,请有相关网络方面经验的高手多多探讨, 现在已经测试过加大系统缓冲的做法, 效果不是很明显。
...全文
25748 60 打赏 收藏 转发到动态 举报
写回复
用AI写文章
60 条回复
切换为时间正序
请发表友善的回复…
发表回复
jiaruyz 2012-02-14
  • 打赏
  • 举报
回复
如果客户端采用2003server呢?
linshenqi 2010-12-23
  • 打赏
  • 举报
回复
[Quote=引用 47 楼 jakky520 的回复:]

问题已经解决了,谢谢大家的帮助

问题不是出在服务器端了,我服务器端用的是非阻塞的网络模式,
瓶颈出在客户端,貌似一个PC机上最多只能开到不到4000的socket链接, 服务器端无限制,昨天测试了下
服务器可以最大accept并处理65535个链路的数据。

感谢大家的帮助
[/Quote]
当我看到第3l的时候,我就在想是不是这个问题。果然,看来只能放到多台机器上测了。
jjcheung 2010-10-19
  • 打赏
  • 举报
回复
看来还是楼上贴的MaxUserPort这个注册表限制的,因为客户端connect()时系统选择一个本地端口,这个端口号受MaxUserPort控制的,默认在1024-5000之间,大概3900多个。
luoweisong 2010-04-21
  • 打赏
  • 举报
回复
mark
天地英豪 2009-12-01
  • 打赏
  • 举报
回复
学习了`
jakky520 2009-11-03
  • 打赏
  • 举报
回复
结贴了 :
感谢大家的帮助,感觉这个并发的问题花费了太多的时间,主要还是在于对于系统级别的一些限制不太了解,
对于windows平台和linux平台并发的限制是有多种的,
window平台
在采用非阻塞体系结构,整个socket瓶颈是在于fd_setsize ,因为window系统默认的fd_setsize是64
在winsock2.h里面可以找到
#ifndef fd_size
#define fd_size 64
so ,只要在你所写的代码里面在#include <winsock2.h>前面加上
#ifdef FD_SETSIZE
#undefine FD_SETSIZE
#define FD_SETSIZE 50000即可。
当然, 前提条件还是在你所写代码性能上能够达到上限的基础上的 呵呵。

Linux上面其实类似,
这些我都是在网上找的, 关于linux系统级别的限制在网上可以找的到的 。
rularys 2009-10-01
  • 打赏
  • 举报
回复
这个貌似和系统的资源配置有关系。我在XP上时,服务器最多能开不到4000的套接字,而且到了上限以后,整个系统的所有进程都不能再建立新连接了。但是在Server版OS上(一样的机器),这个数字却不一样,但是都有一个上限值。
wzyzb 2009-09-30
  • 打赏
  • 举报
回复
是啊 楼主总结啊
fangjm2009 2009-09-30
  • 打赏
  • 举报
回复
恭喜楼主,顺便总结总结,大家学习学习啊
makui 2009-09-28
  • 打赏
  • 举报
回复
[Quote=引用 47 楼 jakky520 的回复:]
问题已经解决了,谢谢大家的帮助

问题不是出在服务器端了,我服务器端用的是非阻塞的网络模式,
瓶颈出在客户端,貌似一个PC机上最多只能开到不到4000的socket链接, 服务器端无限制,昨天测试了下
服务器可以最大accept并处理65535个链路的数据。

感谢大家的帮助
[/Quote]

楼主总结一下嘛
尘雨 2009-09-28
  • 打赏
  • 举报
回复
恭喜楼主,呵呵,看来考虑问题要多角度,这都是经验啊
jakky520 2009-09-28
  • 打赏
  • 举报
回复
问题已经解决了,谢谢大家的帮助

问题不是出在服务器端了,我服务器端用的是非阻塞的网络模式,
瓶颈出在客户端,貌似一个PC机上最多只能开到不到4000的socket链接, 服务器端无限制,昨天测试了下
服务器可以最大accept并处理65535个链路的数据。

感谢大家的帮助
crst_zh 2009-09-25
  • 打赏
  • 举报
回复
[Quote=引用 44 楼 xiayadong 的回复:]
引用 31 楼 fangle6688 的回复:
你的IOCP例程逻辑有点问题:

每个客户端连接进来,你都投递了个WSARecv
然后每次WSARecv完成后都继续投递WSARecv

假如你的客户端没有一直向服务端发送数据的话
IOCP队列中未决IO会越来越多

——这已经不是连接瓶颈的问题,而是内存页资源的问题了



正解!
[/Quote]
不会啊,他那个除非有完成通知才会继续下一次投递,
那么如果客户端一直没有发送数据,
GetIoCompletionStatus()就不会返回,也就是说不会进行下一次投递,
所以IOCP队列中未决IO不会越来越多啊

欢迎讨论,只是为了更清晰。
crst_zh 2009-09-25
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 zhaohongbo83 的回复:]
学习  ICOP!
[/Quote]

应该是IOCP!
xiayadong 2009-09-24
  • 打赏
  • 举报
回复
[Quote=引用 31 楼 fangle6688 的回复:]
你的IOCP例程逻辑有点问题:

每个客户端连接进来,你都投递了个WSARecv
然后每次WSARecv完成后都继续投递WSARecv

假如你的客户端没有一直向服务端发送数据的话
IOCP队列中未决IO会越来越多

——这已经不是连接瓶颈的问题,而是内存页资源的问题了
[/Quote]


正解!
xiayadong 2009-09-24
  • 打赏
  • 举报
回复
看你的代码是在一个进程里初始化4000个socket,你试试用多线程,每个线程里用一个socket进行收发数据;
另外注意使用多线程时,一个进程开启的线程数最好控制在1800之内,超出的话,好像socket就连接不上了!

测试的时候可以用多台电脑,开启多个进程进行测试!

你的服务端代码我没研究,说实话,看代码挺头痛!
jakky520 2009-09-24
  • 打赏
  • 举报
回复
[Quote=引用 40 楼 coding_hello 的回复:]
lz不妨试试用多个客户机去连服务器,估计每个客户端机器都能建立3900多个链。

因为默认情况下,只会使用1024-5000之间的端口号,所以极限也不到4000个。
[/Quote]

已经尝试过这样的情况了, 我在一个域里面用3台客户端连接我的服务器 ,每个客户端连接1000路都不到。
我用的是554端口,也改过载1024-5000里面的端口 ,效果基本一样。
jakky520 2009-09-24
  • 打赏
  • 举报
回复
[Quote=引用 37 楼 vieri_ch 的回复:]
你的服务端 监听端口是多少,改成5000以下的端口试试看,感觉这个问题不仅仅是代码上的问题
[/Quote]

我的服务端监听端口是 554 ,是在5000以下 ,现在问题是大概3900路的时候 sokcet就建立不了了。
xiayadong 2009-09-23
  • 打赏
  • 举报
回复
用IOCP吧,我P4 1.7 512内存,两机进行测试的时候,服务端最大可以同时并发3W多的连接(客户端每秒发送数据一次)

我记得一开始的时候用的xp 测试的,最多也只是4K左右的连接,后面就再也连接不上了,后来换了server2003测试才得到3W左右的同时并发数。
jakky520 2009-09-23
  • 打赏
  • 举报
回复
昨天用IOCP的服务器端代码测试了下 ,也不能够支持更多路的并发连接啊 ...最多也只能支持到3973路。大家看下这个代码有问题没?




#include "winerror.h"
#include "Winsock2.h"
#pragma comment(lib, "ws2_32")

#include "windows.h"

#include <iostream>
using namespace std;

/// 宏定义
#define PORT 554
#define DATA_BUFSIZE 8192
#define IP 192<<24|168<<16|30<<8|47

#define OutErr(a) cout << (a) << endl\
<< "出错代码:" << WSAGetLastError() << endl\
<< "出错文件:" << __FILE__ << endl\
<< "出错行数:" << __LINE__ << endl;

#define OutMsg(a) cout << (a) << endl;


/// 全局函数定义

///////////////////////////////////////////////////////////////////////
//
// 函数名 : InitWinsock
// 功能描述 : 初始化WINSOCK
// 返回值 : void
//
///////////////////////////////////////////////////////////////////////
int InitWinsock()
{
// 初始化WINSOCK
WSADATA wsd;
if( WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
return -1;

}

///////////////////////////////////////////////////////////////////////
//
// 函数名 : BindServerOverlapped
// 功能描述 : 绑定端口,并返回一个 Overlapped 的Listen Socket
// 参数 : int nPort
// 返回值 : SOCKET
//
///////////////////////////////////////////////////////////////////////
SOCKET BindServerOverlapped(int nPort)
{
// 创建socket
SOCKET sServer = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);

// 绑定端口
struct sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(nPort);
servAddr.sin_addr.s_addr = htonl(IP);

if(bind(sServer, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0)
{
OutErr("bind Failed!");
return NULL;
}

// 设置监听队列为200
if(listen(sServer, SOMAXCONN) != 0)
{
OutErr("listen Failed!");
return NULL;
}
return sServer;
}


/// 结构体定义
typedef struct
{
OVERLAPPED Overlapped;
WSABUF DataBuf;
CHAR Buffer[DATA_BUFSIZE];
} PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;


typedef struct
{
SOCKET Socket;
} PER_HANDLE_DATA, * LPPER_HANDLE_DATA;


DWORD WINAPI ProcessIO(LPVOID lpParam)
{
HANDLE CompletionPort = (HANDLE)lpParam;
DWORD BytesTransferred;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;

while(true)
{

if(0 == GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (LPDWORD)&PerHandleData, (LPOVERLAPPED*)&PerIoData, INFINITE))
{
if( (GetLastError() == WAIT_TIMEOUT) || (GetLastError() == ERROR_NETNAME_DELETED) )
{
cout << "closing socket" << PerHandleData->Socket << endl;

closesocket(PerHandleData->Socket);

delete PerIoData;
delete PerHandleData;
continue;
}
else
{
OutErr("GetQueuedCompletionStatus failed!");
}
return 0;
}

// 说明客户端已经退出
if(BytesTransferred == 0)
{
cout << "closing socket" << PerHandleData->Socket << endl;
closesocket(PerHandleData->Socket);
delete PerIoData;
delete PerHandleData;
continue;
}

// 取得数据并处理
cout << PerHandleData->Socket << "发送过来的消息:" << PerIoData->Buffer << endl;

// 继续向 socket 投递WSARecv操作
DWORD Flags = 0;
DWORD dwRecv = 0;
ZeroMemory(PerIoData, sizeof(PER_IO_OPERATION_DATA));
PerIoData->DataBuf.buf = PerIoData->Buffer;
PerIoData->DataBuf.len = DATA_BUFSIZE;
WSARecv(PerHandleData->Socket, &PerIoData->DataBuf, 1, &dwRecv, &Flags, &PerIoData->Overlapped, NULL);
}

return 0;
}

void main()
{
InitWinsock();

HANDLE CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);

// 根据系统的CPU来创建工作者线程
SYSTEM_INFO SystemInfo;
GetSystemInfo(&SystemInfo);

for(int i = 0; i < SystemInfo.dwNumberOfProcessors * 2; i++)
{
HANDLE hProcessIO = CreateThread(NULL, 0, ProcessIO, CompletionPort, 0, NULL);
//if(hProcessIO)
CloseHandle(hProcessIO);
}

// 创建侦听SOCKET
SOCKET sListen = BindServerOverlapped(PORT);


SOCKET sClient;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
while(true)
{
// 等待客户端接入
//sClient = WSAAccept(sListen, NULL, NULL, NULL, 0);
sClient = accept(sListen, 0, 0);

cout << "Socket " << sClient << "连接进来" << endl;

PerHandleData = new PER_HANDLE_DATA();
PerHandleData->Socket = sClient;

// 将接入的客户端和完成端口联系起来
CreateIoCompletionPort((HANDLE)sClient, CompletionPort, (DWORD)PerHandleData, 0);

// 建立一个Overlapped,并使用这个Overlapped结构对socket投递操作
PerIoData = new PER_IO_OPERATION_DATA();

ZeroMemory(PerIoData, sizeof(PER_IO_OPERATION_DATA));
PerIoData->DataBuf.buf = PerIoData->Buffer;
PerIoData->DataBuf.len = DATA_BUFSIZE;

// 投递一个WSARecv操作
DWORD Flags = 0;
DWORD dwRecv = 0;
WSARecv(sClient, &PerIoData->DataBuf, 1, &dwRecv, &Flags, &PerIoData->Overlapped, NULL);
}

DWORD dwByteTrans;
PostQueuedCompletionStatus(CompletionPort, dwByteTrans, 0, 0);
closesocket(sListen);
}




加载更多回复(38)

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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