。。。。。。。。。。 (100分)

  • 主题发起人 陈一蛟
  • 开始时间
to 陈一蛟
显然你的速度要快一些,原因是你没有用类的继承方式,负荷就要小一些。。。
 
恕我愚蠢;
讲讲基本概念
阻塞方式: 处理请求后不再相应其他的请求,直到明确返回处理结果.再响应其他的请求
非阻塞的方式;处理请求后,用另外一个线程处理其他的请求,再响应其他的请求。

TCP/UDPServer 的工作模式.
单线程模式/多线程模式:
监听/转发.
1 - N 模式:
1 - 1 模式:

完全端口模式:我猜的. 是不是将监听端口累加,绑定新端口与客户端通信.

还请指正.
另有个问题:不知道大家如何控制影响响应时间的业务的.比如:查询请求.如果过久没有相应
服务器就会死掉,至少线程是死的了.
...........

 
[red]查询请求.如果过久没有相应服务器就会死掉,至少线程是死的了[/red]
 ---- 呵呵,关注这个问题。
 
谈谈我的看法。
to itren:
阻塞模式:接收线程始终处于等待状态,直到有数据到达时被唤醒。
非阻塞模式:无需线程,当有数据到达时,通过异步方式通知应用程序接收数据。异步方式
包括:消息方式、事件方式。
完成端口:重叠端口的一种特例,要明白完成端口必先明白重叠端口。其实质是最高效地利
用操作系统的调度功能。当Socket上有事件发生时通知工作者线程处理数据。
BTW:任何方式都不可能实现Socket的并行处理。

to 张无忌:
一、我始终不明白你说的类的继承会影响运行效率的依据何在。可能从第一天学习面向对象
开始你就形成了这种印象,先入为主。但事实上并非如此。没有继承就不可能有多态,而没
有多态的类与结构及寄存器函数何异。继承的机制只可能增加一点点VMT的开销,运行的时
候也是从一个地址取调用入口。这和调用一个寄存器函数在时间效率上几乎没有区别(仅仅
只是far调用与near调用的区别)。我看过面向对象程序生成的二进制代码,并专门分析过。
事实上恰好相反:继承机制会提高二进制代码的效率----因为当对象实例较多时会大幅度减
少判断指令。

二、消息模式是最差的异步方式这点我也不能同意。对于主线程的消息队列可能效率较低:
因为主线程还需要接收来自所有子窗口的消息,而且对于可视化窗口而言,处理一个消息可
能会在消息队列增加两三个其它的消息。但如果主线程只处理Socket消息(对服务器而言)则
决不会比事件或信号量低效。为什么?Master Delphi6上说处理一个信号量需要数百个时钟
周期,事件也需要数十个时钟周期。而消息呢?一般不足10个时钟周期。说消息机制的系统
开销大则更没有依据。因为Windows分分钟需要处理成千上万的消息,所以,M$将消息处理
机制可能用到的系统开销缩到最小。首先传递参数的时候使用最高效的PASCAL方式;其次,
处理消息时只需要返回True或False系统就判定需不需要调用缺省窗口过程。处理完事件的时
候需要调用ResetEvent这个API来复位。而使用消息带来的好处则是数不胜数:不需要太多的
堆栈开销;不需要考虑事务逻辑结构;可以不增加任何开销地传递任何参数。参数个数不够
还可以借助结构甚至对象。
对于线程消息处理则更是高效。一旦有消息进入线程的消息队列,msgWaitForMultipleObjects
函数立刻响应,根本不可能比响应其它内核对象慢。

to 陈一蛟:
一、Socket效率的高低与采用线程阻塞方式(不要简化成“阻塞方式”)或异步方式没有必然
的联系。本身线程阻塞方式/异步方式并不是Socket概念中的,而是WinSocket中的。WinSocket
实现Socket标准时采用了多种可选的方式,这只是客户端常用的两种。而服务端还可以采用
重叠端口和完成端口(仅限Windows2000)。阻塞方式只是对原生的异步方式的一种优化,为
了满足系统其它方面的需要。在阻塞方式中仍然需要调用原生的异步方式的函数,其区别就
在于是否使用线程。很显然,系统对线程的依赖性就决定了这两种方式处理数据包的效率。

二、所谓线程Pool和线程Cache,据我看的原码与你说的有些区别。客户端不需要线程池这个
东东。服务端对线程的管理并不是说事先准备好100线程等候100个连接。在MIDAS中很明显:
线程CacheSize只有10,但100个连接没有问题。最开始的时候并不建立线程,一个客户连接,
建立一个线程,当客户断开后,并不清除线程(Delphi的线程开销太大),只有当并发的连接
数超过指定的CacheSize后,客户断开连接后会释放线程。不管连接数是否超过CacheSize,
只要有新的连接,系统都会接受。换句话说,CacheSize只管线程的释放,而不管线程建立。

三、TWSocket好象有些老了,多年以前我用它写过Chat之类的程序。相比之下,Delphi自带
的SocketComponent更可靠。TTCPBlockSocket我没有用过。但类似
repeat
s := FSock.RecvString(90000);
if s <> '' then
begin
Flag := True;
Break;
end;
until FSock.LastError <> 0;
这样的代码在线程中使用...MyGod!我看还是别用了,让你对线程阻塞模式产生误会。千万别
将它的帐记在WinSocket的模式上。可惜我的代码不能供你测试,我可是线程阻塞和非阻塞都有
的。以下是我的客户端线程代码:
procedure TSocketClientThread.Execute;
procedure SynchronizeException;
var
SendException: TObject;
begin
SendException := AcquireExceptionObject;
PostMessage(FSocketClient.Handle, CM_ERROR, - 1,
Integer(Pointer(SendException)));
end;
var
Msg: TMsg;
Share: Boolean;
Data: TDataBlock;
begin
//疏通线程消息渠道
PeekMessage(Msg, 0, WM_USER, WM_USER, PM_NOREMOVE);
//通知客户端线程已启动
ReleaseSemaphore(FSemaphore, 1, nil);
//循环开始
while not Terminated and FSocketClient.Active do
try
//等候事件
case MsgWaitForMultipleObjects(1, FEvent, False, INFINITE, QS_ALLINPUT) of
WAIT_OBJECT_0:
begin
WSAResetEvent(FEvent);
//通知客户端收报
FSocketClient.WinSocket.Post;
end;
WAIT_OBJECT_0 + 1:
begin
//所有消息均来自发送数据机制
while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do
if (Msg.hwnd = 0) then
case msg.message of
CM_DATA:
begin
//共享标记确定发送完是否释放包
Share := Msg.wParam <> 0;
Data := TDataBlock(Pointer(Msg.lParam));
if FSocketClient.Active then
//传送过程释放该数据包
FSocketClient.WinSocket.Send(Data, Share)
else
//如果Socket已断开,则直接释放该数据包
if not Share then
Data.Free;
end;
else
DispatchMessage(Msg);
end
else
DispatchMessage(msg);
end;
end;
except
SynchronizeException;
end;
end;
说明:FSocketClient是应用程序对象,管理该线程;FSocketClient.WinSocket是数据处理
器,具有Post和Fire两上关键方法,管理数据包的组包和拆包。TDataBlock是数据包对象。
 
。。。。。。。。。。。。。。。。。。
 
to barton:
第一,继承确实影响效率,很多对效率要求比较高的开发项目都不会用C++,
很多PDA和个人掌上设备的地层开发都是用C,虽然说现在有人用JAVA,但是
一直都不上台面,
第二,消息模式开销比你想象的要的多,他要判断发送消息的线程,要判断
消息的标志和消息类型,开销比你想象的要大的多,
下面就是MS的测试结果,你看看实际的情况如何,组塞和消息模式是效率最
低的,事实如此,不知道你有看法?
I/O Model Attempted/Con nected Memory Used (KB) Non- Paged Pool CPU Usage Threads Throughput (Send/ Receive Bytes Per Second)
Blocking 7000/
1008 25,632 36,12 1 10– 60% 2016 2,198,148/
2,198,148
12,000/
1008 25,408 36,35 2 5–40% 2016 404,227/
402,227
Non-
blocking 7000/
4011 4208 135,1 23 95– 100 %* 1 0/0
12,000/
5779 5224 156,2 60 95– 100 %* 1 0/0
WSA-
Async
Select 7000/
1956 3640 38,24 6 75– 85% 3 1,610,204/
1,637,819
12,000/
4077 4884 42,99 2 90– 100 % 3 652,902/
652,902
WSA-
Event
Select 7000/
6999 10,502 36,40 2 65– 85% 113 4,921,350/
5,186,297
12,000/
11,080 19,214 39,04 0 50– 60% 192 3,217,493/
3,217,493
46,000/
45,933 37,392 121,6 24 80– 90% 791 3,851,059/
3,851,059
Over-
lapped (events) 7000/
5558 21,844 34,94 4 65– 85% 66 5,024,723/
4,095,644
12,000/ 12,000 60,576 48,06 0 35– 45% 195 1,803,878/
1,803,878
49,000/ 48,997 241,208 155,4 80 85– 95% 792 3,865,152/
3,834,511
Over-
lapped (comple-
tion port) 7000/
7000 36,160 31,12 8 40– 50% 2 6,282,473/
3,893,507
12,000/ 12,000 59,256 38,86 2 40– 50% 2 5,027,914/
5,027,095
50,000/ 49,997 242,272 148,1 92 55– 65% 2 4,326,946/
4,326,496

具体的信息在http://www.microsoft.com/mspress/books/sampchap/5726a.asp
 
WSA-AsyncSelect 7000/1956 你看看你认为效率很高的消息模式7000个并发连接只能处理
1956个,而你认为开销很大的EVENT模式WSA-EventSelect 7000/6999 的测试结果是能处
理6999个并发连接, 难道MS的测试有问题???上面的测试结果是完成端口效率最高,
Event模式也不错,适合在98/NT/2000下开发高性能网络程序使用,我也是一直用这种模
式,感觉很不错,稳定,使用起来很顺手,EVENT模式天生就是线程使用的,很适合做
服务器类的开发
 
当然效率最烂的是组塞模式7000/1008,7000个并发连接只能处理1008个,
这也说明INDY的工作模式是不太好的,只适合小的应用,
 
张无忌的看法还是比较正确的,
首先,楼主的测试有问题,特定的测试并不能得出这样的结论,组件之间的差别也是有的
用同一个组件做出来的结果还有可信性,

我也觉得线程模式比消息模式效率要搞得多
 
呵呵,看来我插不上话啦.听课.
顺便问一下并发连接如何测试?
 
MS的测试方式一个台服务器,其他的客户机一起去连接,MS有钱!
 
。。。。。。。。。。。。。。。。。
 
在服务器中效率高的I/O模式做客户端效率当然比那些效率低的I/O模式要好,
这个是必然的,他是并发连接,也就是同时处理多个连接,不是一个一个的
上的
 
阻塞模式的服务器是不是这样两个工作方式?
1.客户连接有一个队列,有个线程池.用一定数量的线程去处理客户队列.例如用100个线程去处理1000个客户连接.
2.简单的有一个客户就创建一个线程去处理.这样会有线程上限吗?大概是多少?
m$的测试1008个连接是指第二种连接方式么?

另外我想想问的是 消息和事件模式有什么大概的区别. 消息和事件的概念我知道.
消息异步模式好像是有数据到达的时候会发一个消息给程序的消息循环,然后在消息处理过程里面处理.
事件模型是如何工作? 用线程waitEvent?请介绍一下.

 
,,,,,,,,,,,,,,,,,,
 
。。。。。。。。。。。。。。。。。。。。
 
to 张无忌:
对于第一个问题,我还是不能接受。PDA上不用继承可能与内存开销有关,与运行效率无关。
对象实例增加的确会增加内存空间的消耗,毕竟VMT是个无底洞。在PC平台上,内存上的消耗
与良好的程序结构相比,我更倾向于使用继承。
对于第二个问题,有M$的详细测试数据,比较有说服力。重叠端口居然顶不上事件异步,令
我非常奇怪。如果是这样的话,大家都用事件异步好了。毕竟完成端口只能用于WindowsNT/2000。
事件异步处理起来一点不比消息异步复杂。纯阻塞模式谁也不会用。
 
假定每个线程处理10个连接,则可以建立一个事件句柄数组,等待函数等待事件触发,
然后分解网络事件并调用Socket的事件处理。
to 陈一蛟:
FD_READ事件次数多于有数据到达的次数?那你检查没有数据到达的FD_READ事件中还有
别的事件发生吗?
 
另:你的SocketClient似乎更多地吸收了TWSocket。Delphi的ClientSocket错误处理交由
Windows处理的。这样显示出来的错误信息规范。
 
顶部