Indy的TCPServer到底能支持多少个连接
最近一个项目,最开始使用IdTcpServer,在大压力测试的时候,只连接了800个多一点的客户端(每个客户端连接上之后每秒钟发送一个几十字节的报文,服务器应答)。但是持续的时间不会超过10分钟,服务器就会挂掉(经常是服务器突然关闭消失,任何提示都没有)。后来优化了互斥量之后,可以连接到1000多个客户端。但是服务器消失的问题依然存在。
今天再一台双CPU,4G内存的服务器上试验了下,居然最也只能连接到2000多个客户端。然后换了Indy10.1.5服务器只做简单的连接和应答,客户端连接之后只发送一个报文,还是一样,服务器最多只能连接2000多个客户端。
然后下载了Indy10的官方帮助文件(http://www.projectindy.org/downloads/IndyDocs_10.1.5.0_HtmlHelp.zip)它的TCPServer帮助里面有一段话:
But there are performance and resource limitations imposed by the platform or Operating System on the number of threads that can be created. On Windows, for example, the number of threads is limited by the available virtual memory. By default, every thread gets one megabyte of stack space and implies a theoretical limit of 2028 threads. Reducing the default stack size will allow more threads to be created, but will adversely impact system performance.
意思理论上Windows的操作系统最多支持2028个线程。于是昏倒了。因为我们的客户端最少也会有5000个呀。
后来有换了delphi的异步非阻塞TCPServer,测试连接了15000个客户端都没有啥问题。
难道Indy真的只能支持到2000多个客户端连接?
各位大侠有用过Indy的TCP服务器的,你们的服务器可以连接多少客户端呀?
没做过这中压力测试得呢
真有这么大量的连接,建议做IOCP+WinSock API,别用控件的
Windows的操作系统不一只支持2028个线程的!
用CreateThread测试,数万个都OK的,只是越来越慢而已
大量的连接非常注重内存泄漏等问题的,并需要修改源码的
Indy10支持IOCP和纤程,不过要安装SuperCore包(默认没有),并设置Server的IOHandle,否则Indy10的效能在Windows和Indy9一样
减少线程的stack空间可以增加线程数量,
或者在xp+(只是xp+,不包括win2k)的boot.ini中加上/3GB选项也可以增加进程可用的地址空间。
但是不管怎么说,
在32-bit的Windows上,最多的同步线程在2000~3000这个水平。
支持更多的用户可以使用分布式处理,即你的主服务器把试图连接的客户端分配到其他服务器去。象QQ、hotmail之类的都是这么处理的,
每次你连接的都是www.hotmail.com,但是具体完成服务的可能是xxxxx.xxxx.hotmail.msn.com之类的。
一台服务器能够处理2000个连接已经不错了,多搞几台服务器吧。
To ly_liuyang,THX,看了IOCP,还没有开始做就昏了。明天继续学习。
To getit911,THX,我怎么安装不了SuperCore的包呀,编译通不过,你是怎么安装的?我也看到Indy的帮助说纤程,当时也奇怪,怎么他的IOHandler里面没有这个东西,都是线程的。
再顶一下,明天来结分。
indy的tcpserver使用的io模型是多线程阻塞socket,对超过1000的并发连接,并不是好的选择,indy10并不支持iocp,里面的纤程是针对unix传统的多进程模型在windows上的移植.这样的情况,建议使用iocp,看看msdn,自己写吧,也不是很复杂
用一个线程绑定一个客户连接,效率比较差了,
对于密集型的应用,不能用indy这样的控件,他太复杂了,反而没有效率了。
对于这样的应用,只能采用非阻塞的方式了,虽然比较麻烦,但是只有这个办法,让一个线程为多个客户服务。
同时,要使用线程池,不要客户断开就释放线程,线程可以挂起留着再用。
分布式处理是最佳途径。
多增加几台服务器的硬件价格是微不足道的,
即使你使用更复杂的模型,完成端口+线程池,
所能增加的用户数量也是有限的,也就5%吧。
而且这种模式也是难以移植的。
我又想到了一个提高负载的办法。
就是创建多个进程,单一进程的线程数量是受到限制的,但是,使用多个进程就能避免这个结果。
可以根据负载情况,灵活的增加进程数量,但是,一个进程只能打开一个同一个端口的句柄,好像有一个复制句柄的方式,让别的进程共享同一个Socket句柄。
如果实现这个,就不受线程数量的限制了,不过,我不是很清楚windows在实现阻塞Socket的方式,阻塞的好像是循环的,不能释放线程的,效率低下,应该使用异步Socket,这样才能让等待线程挂起。
楼上的,不可能。
一个系统中总的线程数量是有限的,这是因为
每一个线程都要分配一个TCB,4KB,这个是不能交换到虚存的,另外还要分配局部stack。
内存空间的限制决定了线程的数量不可能很多。
而且活跃线程增加到一定程序,系统的响应速度就严重降低了。
多个进程远远比多线程更耗资源..
如果是多用户长连接,可以考虑使用IOCP,用少量线程服务大量客户.
至于线程池,倒是一般都用到的..主要能在大量短连接通讯时候起作用.
Woo~看来讨论挺激烈呀。再加些分。多讨论下。
用纯Winsock API做了一个简单的TcpServer,没有IOCP
采用线程方式,一个服务器最多也只能创建2000个左右的连接线程,之后出现10053(软件造成连接取消)错误。证明不是Indy控件的问题。
接下来再试试异步方式。
Winsock API的程序代码如下:
program WinSockSvr;
{$APPTYPE CONSOLE}
(*-------------------------------------------------------------------
说明:TCP/IP 服务器演示程序 Ver0.1
采用标准WinSock2.2 API函数
采用线程堵塞模式,每个客户端连接创建一个收发线程。
作者:Zuni
时间:2006-3-20
使用到的函数说明:
WSAStartup //初始化WinSock
WSACleanup //释放WinSock引用
socket //创建Socket,对服务器来说,就是创建侦听Socket
bind //绑定侦听套接字到本机
listen //开始侦听
accept //接受客户端连接
recv //从套接字接受数据
send //向套结字发送数据
closesocket //关闭套接字
getpeername //获取套接字的客户端的TSockAddr结构
inet_ntoa //把IPv4网络地址转成点分地址
ntohs //网络字节序转换成主机字节序
htons //把主机字节序转成网络字节序
-------------------------------------------------------------------*)
uses
WinSock, System, SysUtils, StrUtils, ScktComp, Windows;
const
DEF_BUF = 4095;
var
iPort : Integer = 2004;
bEcho : Boolean = True;
iCount : Integer = 0;
procedure Useage;
begin
WriteLn('usage: WinSockSvr [-p:x] [-o]');
WriteLn(' -p:x Port number to listen on');
WriteLn(' -n: Do not echo the receved world');
WriteLn('');
Halt;
end;
procedure DoArgs;
var
i : Integer;
s : string;
sv : string;
begin
// if ParamCount<1 then
// Useage;
for i:=1 to ParamCount do
begin
s := ParamStr(i);
sv := RightStr(s, Length(s)-3);
if (s[1]='-') or (s[1]='/') then
begin
try
case UpCase(s[2]) of
'P': iPort := StrToInt(sv);
'N': bEcho := False;
end;
except
Useage;
end;
end else
Useage;
end;
end;
function ClientThread(Param: Pointer): Integer; stdcall;
var
iRet : Integer;
s : TSocket;
saPeer : TSockAddr;
cBuf : array[0..DEF_BUF] of Char;
sBuf : string;
iLeft : Integer;
idx : Integer;
i : Integer;
begin
s := TSocket(Param);
i := SizeOf(saPeer);
getpeername(s, saPeer, i);
while True do
begin
iRet := recv(s, cBuf, DEF_BUF+1, 0);
if iRet=0 then
begin
WriteLn(Format('Client(%s:%d) is close gracefully', [inet_ntoa(saPeer.sin_addr), saPeer.sin_port]));
closesocket(s);
DEC(iCount);
Break;
end;
if iRet=SOCKET_ERROR then
begin
WriteLn('recv() function failed, Error code', WSAGetLastError);
closesocket(s);
DEC(iCount);
Break;
end else
begin
cBuf[iRet] := #0;
Write(Format('Get message from %s:%d ', [inet_ntoa(saPeer.sin_addr), saPeer.sin_port]));
SetLength(sBuf, iRet);
sBuf := cBuf;
WriteLn(sBuf);
end;
//发送反馈
if bEcho then
begin
sBuf := 'You sent message: '+ sBuf;
iLeft := Length(sBuf)+1; //加1是为了多加个换行符
for i:=0 to iLeft-2 do
begin
cBuf[i] := sBuf[i+1];
end;
cBuf[iLeft-1] := #10;
idx := 0;
while (iLeft>0) do
begin
iRet := send(s, cBuf[idx], iLeft, 0);
if iRet=0 then
begin
WriteLn(Format('Client(%s:%d) is close gracefully', [inet_ntoa(saPeer.sin_addr), saPeer.sin_port]));
closesocket(s);
DEC(iCount);
Break;
end;
if iRet=SOCKET_ERROR then
begin
WriteLn('send() function failed, Error code', WSAGetLastError);
closesocket(s);
DEC(iCount);
Break;
end;
iLeft := iLeft - iRet;
idx := idx + iRet;
end;
end;
end;
Result := 1;
end;
var
wsd : TWSAData;
saSrv : TSockAddr;
saClt : TSockAddr;
scktListen : TSocket;
scktClient : TSocket;
iLen : Integer;
hThread : THandle;
dwThreadId : DWORD;
begin
DoArgs;
//初始化WinSock,版本号2.2
if (WSAStartup($0202, wsd)<>0) then
begin
WriteLn('Fail to load WinSock2.2');
Exit;
end else
WriteLn('Step 1: Load WinSock Succ, Current Version: ', IntToHex(wsd.wHighVersion,4));
//创建侦听Socket
scktListen := socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if scktListen=INVALID_SOCKET then
begin
WriteLn('Fail to create a listen socket, Error code: ', WSAGetLastError);
WSACleanup;
Exit;
end else
WriteLn('Step 2: Creat listen socket Succ');
//绑定Listen Socket到本机
saSrv.sin_family := AF_INET;
saSrv.sin_port := htons(iPort);
saSrv.sin_addr.S_addr := htonl(INADDR_ANY);
if bind(scktListen, saSrv, SizeOf(saSrv))=SOCKET_ERROR then
begin
WriteLn('Fail to bind the listen socket, Error code: ', WSAGetLastError);
Closesocket(scktListen);
WSACleanup;
Exit;
end else
WriteLn('Step 3: Bind Succ, Listen port is ' , saSrv.sin_port );
//开始侦听
if listen(scktListen, SOMAXCONN)=SOCKET_ERROR then
begin
WriteLn('Fail to listen, Error code: ', WSAGetLastError);
Closesocket(scktListen);
WSACleanup;
Exit;
end else
WriteLn('Step 4: Listening......');
WriteLn('');
while True do
begin
//接受客户端连接
iLen := SizeOf(saClt);
scktClient := accept(scktListen, @saClt, @iLen);
if scktClient=INVALID_SOCKET then
begin
WriteLn('Fail to accept a client connect, Error code: ', WSAGetLastError);
Break;
end else
WriteLn('Accept client: ', inet_ntoa(saClt.sin_addr), ':', ntohs(saClt.sin_port));
//创建客户端通讯线程
hThread := CreateThread(nil, 0, @ClientThread, Pointer(scktClient), 0, dwThreadId);
if hThread=0 then
begin
WriteLn('Fail to create client thread, Error code: ', GetLastError);
Break;
end;
INC(iCount);
WriteLn(Format('.....................................Count: %d',[iCount]));
CloseHandle(hThread);
end;
closesocket(scktListen);
WSACleanup;
end.
http://blog.csdn.net/tercel99/article/details/46689445
Indy的TCPServer到底能支持多少个连接的更多相关文章
- MySQL到底能支持多大的数据量?
MySQL是中小型网站普遍使用的数据库之一,然而,很多人并不清楚MySQL到底能支持多大的数据量,再加上某些国内CMS厂商把数据承载量的责任推给它,导致很多不了解MySQL的站长对它产生了很多误解,那 ...
- 转:MySQL到底能支持多大的数据量?
MySQL到底能支持多大的数据量? MySQL是中小型网站普遍使用的数据库之一,然而,很多人并不清楚MySQL到底能支持多大的数据量,再加上某些国内CMS厂商把数据承载量的责任推给它,导致很多不了解M ...
- 推荐:实现RTSP/RTMP/HLS/HTTP协议的轻量级流媒体框架,支持大并发连接请求
推荐一个比较好用的流媒体服务开源代码: ZLMediaKit: 实现RTSP/RTMP/HLS/HTTP协议的轻量级流媒体框架,支持大并发连接请求 https://gitee.com/xiahcu/Z ...
- indy tcpclient tcpServer
procedure TForm1.FormCreate(Sender: TObject); begin IdTCPServer1.DefaultPort := ; IdTCPServer1.Activ ...
- ubuntu支持shh远程连接记录
打开终端输入sudo apt-get update更新软件库 在输入sudo apt-get install openssh-server下载ssh sudo /etc/init.d/ssh rest ...
- [C# ASP.NET]如何让IIS Express支持外部(局域网)连接
声明:本文为www.cnc6.cn原创,转载时请注明出处,谢谢! 一.搭建环境: 1.系统:Win10 1809 2.IDE:Visual Studio 2017 3.Framework: 4.6.1 ...
- 让Django支持数据库长连接(可以提高不少性能哦)
书接上回 上回我们说到:<在生产系统使用Tornado WebServer来代替FastCGI加速你的Django应用> 那么现在很流行用一些高性能的nonblock的app server ...
- VMWare 支持的网络连接类型 (VMWare Virtual Network Connection Types)
- CloudFlare上线了新的Proxy Anything选项, 支持转发TCP连接
https://www.nicho1as.wang/articles/cf-proxy-anything.html 申请地址:https://goo.gl/forms/Oc2jyyo0kXsrMyw3 ...
随机推荐
- Python 绝对简明手册
Python 绝对简明手册 help(函数名)来获取相关信息 另外,自带的文档和google也是不可少的 2. 基本语法2.1. if / elif / else x=int(raw_input(&q ...
- Android NumberPicker和DatePicker分割线颜色设置
NumberPicker /** * * 设置选择器的分割线颜色 * * @param numberPicker */ private void setDatePickerDividerColor(N ...
- [Boost]boost的时间和日期处理-(2)时间的操作
<开篇> 本篇紧接着boost上篇叙述Boost::DateTime的时间处理.在C++中,常见的时间有time_t, FILETIME和tm,而boost中用ptime. 构造ptime ...
- Cocos2d-x CCTableView实现列表
在ios程序设计中,会大量使用到tableview视图(UITableView),那么在cocos2d-x中,如果需要类似的列表,该如何实现呢?在引擎中参照ios中的UITableView实现了一个叫 ...
- poj 1155 TELE (树形背包dp)
本文出自 http://blog.csdn.net/shuangde800 题目链接: poj-1155 题意 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构, ...
- 【E2LSH源代码分析】p稳定分布LSH算法初探
上一节,我们分析了LSH算法的通用框架,主要是建立索引结构和查询近似近期邻.这一小节,我们从p稳定分布LSH(p-Stable LSH)入手,逐渐深入学习LSH的精髓,进而灵活应用到解决大规模数据的检 ...
- innerHeight与clientHeight、innerWidth与clientWidth、scrollLeft与pageXOffset等属性
区分innerHeight与clientHeight.innerWidth与clientWidth.scrollLeft与pageXOffset等属性 标签: innerheight clienthe ...
- 【每日一摩斯】-Troubleshooting: High CPU Utilization (164768.1) - 系列5
Oracle(用户)进程 以下这些操作都是需要消耗大量CPU资源的:解析大型查询,存储过程编译或执行,空间管理和排序. 下面这几篇文章可以帮助采集关于使用高CPU资源的进程的更多信息: Note:35 ...
- linux环境: shell初始化文件, for TCSH, CSH
TCSHELL, CSHELL 配置文件 全局配置文件 /etc/csh.cshrc个人配置文件 ~/.cshrc或~/.tcshrc 参考: 1.配置你的csh/tcsh, https://wik ...
- Java面试题精选(二)线程编程、数据库理论和Jdbc部分
—— 线程编程.数据库理论和Jdbc部分内容 —— 数据库的开发应用想必是我们日常所碰到最多的知识点了,大致可分为:oracle.MySQL.SQL Server.Hadoop. NoSQL. ...