为何IOCP能够同时处理成千上万个连接???(20分)

M

mill666

Unregistered / Unconfirmed
GUEST, unregistred user!
看了IOCP文章,有个问题一直郁闷:
IOCP根据CPU的数量,创建CPU*2个线程来处理客户端的请求,如果我只有一个CPU,那么这个线程数就是2,我们就叫它ThreadA和ThreadB;
问题是,如果处理客户请求的过程很耗时,比如是文件传输服务器ftp,如果TheadA正在服务某个客户端ClientA,ClinetA请求传输好几百兆的数据,那么线程ThreadA就一直在为ClientA服务,说不定好几个小时哟【因为文件有好几百兆啊】,如果另外一个客户ClientB也提交了一个几百兆的文件请求,那么ThreadB为ClinetB服务,估计也是要很长时间。

如果这个时候再来一个客户端ClinetC请求,那么这个服务器拿什么线程为ClinetC服务??
这样的法,服务器不就是只能同时处理2个客户端了???

当然,我的理解是错误的,因为Iocp确实能够处理多个客户端,可是我觉得郁闷的地方就是这种处理客户端请求需要很长时间的情况下,为什么还能处理多个客户端???

我看网络上很多关于IOCP的例子都是举例echo服务器,这种服务器处理客户端请求不费时,所以线程利用率就很高。

问题是处理客户端请求 需要很长时间的情况下,怎么能处理多个客户端??
 
S

starpc

Unregistered / Unconfirmed
GUEST, unregistred user!
系统处理多个线程时采用的是分时分片机制,比如把时间分成100ms一片.分别对a,b c...用户响应.
第一轮,先对a服务100ms,再对b服务100ms,...
接着第二轮....
依次类推...
 
M

mill666

Unregistered / Unconfirmed
GUEST, unregistred user!
startpc大侠:
我问的并不是你答的。不知道你对IOCP模型了解吗?
我问的是IOCP模型中,只创建了CPU*2个工作线程,我的CPU只有一个,那么就是创建两个线程了,就这么两个线程怎么同时服务成百上千个客户端?
你回答的只是CPU怎么分配时间服务于线程。
 

金卡绣球jk8.com

Unregistered / Unconfirmed
GUEST, unregistred user!
有收发线程缓冲,处理缓冲
 
M

mill666

Unregistered / Unconfirmed
GUEST, unregistred user!
金卡绣球jk8.com,
你回答的台言简意赅了,能否详细些???
 

东兰梦舞

Unregistered / Unconfirmed
GUEST, unregistred user!
mill666 有: 79个待答问题, 5个已答问题, 回答了: 0 个问题。


太多贴没结了。诚信程度低。
 
M

mill666

Unregistered / Unconfirmed
GUEST, unregistred user!
东兰梦舞:
你去看我那些问题,大多没有得到满意或者正确的回答,为何要结???
再说,在这里不跟你谈论这个问题。
这里的分数对大家其实都不重要,关键是把问题搞清楚了,这样才是你上这个论坛的最终目的。难道你上这个论坛就是为了得这个分??很多人靠灌水,答非所问,得再多的分也是枉然啊。
 
D

delphfans

Unregistered / Unconfirmed
GUEST, unregistred user!
呵呵 线称和连接有什么关系呀,连接就要线称码。你得想法不对。select 湿一种模式而已。是用线称及时得收发数据而已。连接和现成不是对应得关系。iocp 也没有说得那样好。在400连接以下,连接模式对系统性能没有影响。 只是多得时候线称得切换慢了些所以效率底。只是windows处理得问题,用delphi带得做得程序在linux系统直接就可以运行效率很高,iocp只能windows下运行, 开得线称得多少和cpu没有直接得关系,只是实际效率问题。 iocp里用得是完成端口api 对连接管理得方式。
 
S

sllin

Unregistered / Unconfirmed
GUEST, unregistred user!
楼主没有搞清楚线程的概念阿,现成的多少与 干的活的数目 没有关系阿,一个thread也可以 同时 干很多个工作阿
 
M

mill666

Unregistered / Unconfirmed
GUEST, unregistred user!
IOCP大量的使用在游戏开发上,那可不是光几百个连接。
网络上举例了很多关于IOCP的例子,大部分是些echo例子,这种就没有处理客户请求的问题了,直接把客户送来的消息返回给客户。
大家不知道有没有看到过IOCP的模型,都是根据系统的CPU数量,创建CPU*2个线程后,这些线程通过调用函数 GetQueuedCompletionStatus 从完成端口上去取消息,取玩消息后进行处理,其实完成端口就是个消息队列,客户端来了请求则压入队列,这些线程从队列中取消息。我的CPU数量是1,那么这个线程数就是2了。
比如线程ThreadA和ThreadB,如果我处理客户端请求的程序比较耗时【现实中也是这样的,光一个echo没有什么意思】,那么线程ThreadA和ThreadB在一定的时间内就一直在处理客户端的请求,那么在这个时间内,还有线程去取完成端口的队列吗??新的客户端请求来了,就得等ThreadA干完所有事情后进入下一个循环后调用 GetQueuedCompletionStatus 的时候才能被取得,意思是这样的:ThreadA和ThreadB的模型是这样的:
while(true)
begin
GetQueuedCompletionStatus (......);
.......
processclientrequest(....) //process the client request
......
end;
大家可以看到,如果processclientrequest()耗时比较长,那么线程就有点像是“阻塞”于processclientrequest()一段时间,直到 processclientrequest()完成后,才进入下一个循环,才继续 GetQueuedCompletionStatus 去取完成端口队列,处理新的客户端请求。

那么在一定的时间内,这两个线程都“阻塞”于processclientrequest(),哪来的线程可以去处理新的客户端???说白了就是哪来的线程去执行函数GetQueuedCompletionStatus ???
 

寻路

Unregistered / Unconfirmed
GUEST, unregistred user!
我对完成端口并不十分熟悉,随便说说.
记得当时学习完成端口的时候,有看到完成端口的适用范围是在:拥有大量并发操作,但单笔数据量较小的情况下面推荐的.
我个人认为你可以把收到的数据拷贝到一个列队中去,建立专门的处理线程来操作,应该可以减缓问题.但大批量数据似乎并不适合完成端口!
 
D

delphilxh

Unregistered / Unconfirmed
GUEST, unregistred user!
估计你socket工作原理你没有搞清楚,ftp传再大的东西也不是一下都发过来的,而是一包一包发的,没个包的大小一般在1024左右,如果有很多个连接,那就是哪个包来了处理那个
 

爱元元的哥哥

Unregistered / Unconfirmed
GUEST, unregistred user!
我的一些理解,仅供参考:

Windows NT内核采用DPC调用机制,linux2.6内核采用软中断,在早期的linux2.4中采用底半(half-bottom)处理机制。举例:系统收发数据还是在网卡的基础上来处理的,当网络数据来临时,网卡进行物理层的判别,对于需要上传的数据产生中断IRQ请求,根据系统8259可编程中断控制器的设置,操作系统在单个时钟周期内对中断作快速处理(复制数据到socket的buf中,这个buf在windows里面默认是32K,在linux也相同,详细的你可以看windows和linux的代码),处理中断的时候CPU会调用自旋锁锁定,也就是屏蔽其他的中断请求,如果网卡的硬件缓冲区很小,你的网卡收了大量的包,就会在这个时候丢包,但是对于多CPU的系统,每个CPU可以独立的响应中断,所以可以减少掉包的比率。对于这个中断处理操作系统是尽量快速响应的,windows的网络性能和linux的内核性能差别是不大,(题外话:可惜windows将图形处理也加入了内核,也就是在ring0上,这样会占用一定的CPU周期,linux也就没有这样的问题,而且windows还支持会话层,一个数据包经历了那么多的dll,呵呵,真够累的)然后压入队列中进行DPC延迟处理,完成后将自动通知完成历程。

完成端口是微软根据windows的特点对bsd socket的作的特殊扩展,在linux里面就没有完成端口,呵呵,我自己做大规模响应都自己写驱动,在ring 0层直接收发数据,比完成端口的效率还要高一些。
 

金卡绣球jk8.com

Unregistered / Unconfirmed
GUEST, unregistred user!
Re:"那么线程ThreadA就一直在为ClientA服务"

如果是那样堵塞,就不叫iocp了;

至少有一个处理收发数据的,和一个专门处理数据的在干活;
 
D

delphfans

Unregistered / Unconfirmed
GUEST, unregistred user!
错一个监听的,一个接收数据的就可以了
 
B

Beyondbill

Unregistered / Unconfirmed
GUEST, unregistred user!
首先.做为完成端口的基础,我们应该理解重叠IO,这需要你已经理解了内核对象及操作系统的一些概念概念,什么是信号/非信号态,什么是等待函数,什么是成功等待的副作用,什么是线程挂起等,如果这些概令还没有理解,你应该先看一下Windows 核心编程中的相关内容.如果已经理解这些,那么重叠IO对你来说并不难.

你可以这样认为重叠IO,现在你已经进入一个服务器/客户机环境,请不要混淆概念,这里的服务器是指操作系统,而客户机是指你的程序(它进行IO操作),是当你进行IO操作(send,recv,writefile,readfile....)时你发送一个IO请求给服务器(操作系统),由服务器来完成你需要的操作,然后你什么事都没有了,当服务器完成IO请求时它会通知你,当然在这期间你可以做任何事,一个常用的技巧是在发送重叠IO请求后,程序在一个循环中一边调用PeekMessage,TranslateMessage和DispatchMessage更新界面,同时调用GetOverlappedResult等待服务器完成IO操作,更高效一点的做法是使用IO完成例程来处理服务器(操作系统)返回的结果,但并不是每个支持重叠IO操作的函数都支持完成例程如TransmitFile函数.

一个完成端口其实就是一个通知队列,由操作系统把已经完成的重叠I/O请求的通知放入其中。当某项I/O操作一旦完成,某个可以对该操作结果进行处理的工作者线程就会收到一则通知。

以上文字从<WindowsSockets2-使用完成端口高性能,可扩展性Winsock服务程序>和<用完成端口开发大响应规模的Winsock应用程序.doc>文章中摘录,仅供参考
 

守望天使

Unregistered / Unconfirmed
GUEST, unregistred user!
微软在Winsock2中引入了IOCP这一概念 。IOCP全称I/O Completion Port,中文译为I/O完成端口。IOCP是一个异步I/O的API,它可以高效地将I/O事件通知给应用程序。与使用select()或是其它异步方法不同的是,一个套接字[socket]与一个完成端口关联了起来,然后就可继续进行正常的Winsock操作了。然而,当一个事件发生的时候,此完成端口就将被操作系统加入一个队列中。然后应用程序可以对核心层进行查询以得到此完成端口。
这里我要对上面的一些概念略作补充,在解释[完成]两字之前,我想先简单的提一下同步和异步这两个概念,逻辑上来讲做完一件事后再去做另一件事就是同步,而同时一起做两件或两件以上事的话就是异步了。你也可以拿单线程和多线程来作比喻。但是我们一定要将同步和堵塞,异步和非堵塞区分开来,所谓的堵塞函数诸如accept(…),当调用此函数后,此时线程将挂起,直到操作系统来通知它,”HEY兄弟,有人连进来了”,那个挂起的线程将继续进行工作,也就符合”生产者-消费者”模型。堵塞和同步看上去有两分相似,但却是完全不同的概念。大家都知道I/O设备是个相对慢速的设备,不论打印机,调制解调器,甚至硬盘,与CPU相比都是奇慢无比的,坐下来等I/O的完成是一件不甚明智的事情,有时候数据的流动率非常惊人,把数据从你的文件服务器中以Ethernet速度搬走,其速度可能高达每秒一百万字节,如果你尝试从文件服务器中读取100KB,在用户的眼光来看几乎是瞬间完成,但是,要知道,你的线程执行这个命令,已经浪费了10个一百万次CPU周期。所以说,我们一般使用另一个线程来进行I/O。重叠IO[overlapped I/O]是Win32的一项技术,你可以要求操作系统为你传送数据,并且在传送完毕时通知你。这也就是[完成]的含义。这项技术使你的程序在I/O进行过程中仍然能够继续处理事务。事实上,操作系统内部正是以线程来完成overlapped I/O。你可以获得线程所有利益,而不需要付出什么痛苦的代价。

以上摘自 《理解I/O Completion Port》( nonocast原作)
全文地址 http://topic.csdn.net/t/20040512/08/3056877.html 仅供参考
 
J

jingtao

Unregistered / Unconfirmed
GUEST, unregistred user!
爱元元的哥哥:我觉得你的理解是错误的.TCP本身就有数据包确认重发机制,并不会存在真正的丢包现象.

&quot;呵呵,我自己做大规模响应都自己写驱动,在ring 0层直接收发数据,比完成端口的效率还要高一些。 &quot;
自己直接收发数据效率绝对不可能比完成端口效率高.因为你得到的是裸IP数据.而数据包本身会存在重发包(例如,某个数据包接收方反馈确认过慢,于是发送方以为丢包,所以重发)和乱序包(例如,数据包3比数据包1先到达).对于这些情况,你都的先塞到缓冲区排序整理之后再处理(TCP协议栈有部分功能就是干这个的).如果说驱动效率高,除非你写的TCP协议栈比微软写的还高,否则,扯蛋.
另外,很多人总是以为只要跟驱动扯在一起的东西效率就很高,其实不然.驱动写的不好,出问题的机会会多很多,效率也非常低(陆麟就说过:驱动谁都会写,但写的象样的没几个).象TCP这种东西,微软已经做的非常完善了(虽然WINDOWS的BUG多,但不要以为里面的人都是吃素的,全球前10名程序员肯定都在微软,难道你写的比它的更好?).所以我们只需要在上层下功夫即可.因为底层微软已经为我们做的很好了.另外,驱动也不是万能的.说白了,一般涉及硬件IO方面才需要使用驱动.例如,你用驱动来写数据库,不可能效率有多高.
 

爱元元的哥哥

Unregistered / Unconfirmed
GUEST, unregistred user!
[:D]jingtao:你的理解是错误的,物理层和链路层的丢包是大量存在的,否则为什么需要发明TCP协议在IP层来不断的重发保证通讯呢?你说的TCP是在传输层而且是在发送端来负责的事情,跟接受端是没有任何关系的。

在驱动内部来网络通讯的例子大量存在,目前在ISCSI网络存储方案全部都是在驱动内核来做网络通讯,还有微软,IBM的网络备份方案,思科的网络备份方案,甚至包括国内网吧现在大量使用的锐起等无盘方案,Ghost的网络克隆方案,TrueImage的网络克隆方案。包括windows的网上邻居也是在TDI层驱动来直接通讯,入侵检测集群,联动防火墙内部的通讯就更不用讲了,肯定用驱动来收发数据包,甚至我们大家都知道WinpCap方案都在使用驱动来做直接通讯。我想你是见得太少了,所以不要多怪。
 
C

CoolSlob

Unregistered / Unconfirmed
GUEST, unregistred user!
拜一下各路神仙
 
顶部