看了IOCP文章,有个问题一直郁闷:
IOCP根据CPU的数量,创建CPU*2个线程来处理客户端的请求,如果我只有一个CPU,那么这个线程数就是2,我们就叫它ThreadA和ThreadB;
问题是,如果处理客户请求的过程很耗时,比如是文件传输服务器ftp,如果TheadA正在服务某个客户端ClientA,ClinetA请求传输好几百兆的数据,那么线程ThreadA就一直在为ClientA服务,说不定好几个小时哟【因为文件有好几百兆啊】,如果另外一个客户ClientB也提交了一个几百兆的文件请求,那么ThreadB为ClinetB服务,估计也是要很长时间。如果这个时候再来一个客户端ClinetC请求,那么这个服务器拿什么线程为ClinetC服务??
这样的法,服务器不就是只能同时处理2个客户端了???当然,我的理解是错误的,因为Iocp确实能够处理多个客户端,可是我觉得郁闷的地方就是这种处理客户端请求需要很长时间的情况下,为什么还能处理多个客户端???我看网络上很多关于IOCP的例子都是举例echo服务器,这种服务器处理客户端请求不费时,所以线程利用率就很高。问题是处理客户端请求 需要很长时间的情况下,怎么能处理多个客户端??  

解决方案 »

  1.   

    louifox(兰陵笑笑生),
    请问程序里面怎么让你说的“底层”知道要怎么处理客户端的请求?
    就比如这个ftp服务器,至少也要让“底层”知道客户端请求的文件名吧;底层知道了文件名后,底层怎么发送数据给客户端?底层怎么知道是ftp文件传输??
    说白了,就是怎么在程序里面“命令”底层做客户端请求的事情??
      

  2.   

    IOCP的思想是以有限的线程服务n多用户,就是客户多的时候不会有线程闲在那里,所以IOCP不适合那些需要长时间处理客户端请求的应用,有人说IOCP不适合长连接就是这个道理。但并不是说IOCP就不能处理这种应用,这种情况就需要开两个完成端口,一个端口用来响应客户端的连接及数据收发,一个端口处理客户端的业务请求,即数据处理,这个端口的线程就不止两个了,根据客户端的数量来调整的。响应端口接受客户端连接,接收数据后看有无空闲的数据处理线程,有则发送消息给数据处理端口,激活线程,没有空闲线程就再开一个线程进行处理。当然这个数据处理线程的数量是需要控制的,可以看需求是事先开好线程池或是数量动态增长,上限多少等等。
      

  3.   

    herocloud(herocloud) :
         还是不明白啊;你说的提交请求给完成端口,是不是可以这样说,如果是要传世文件,那我就提交个文件传输请求,再加上要传输的文件名??
         可是感觉也不对啊。如果客户端的的请求,需要我在服务端运算一段时间后生成需要的返回结果,说白了,就比如简单的说,客户端提供两个整数A,B,提交给服务端,服务端进行加法运算A+B,那完成端口怎么知道我要做的是A+B这样的事情??
      

  4.   

    IOCP根据CPU的数量,创建CPU*2个线程来处理客户端的请求//==================================================
    IOCP又没有规定你只能创建CPU*2的线程,你创建百来个线程也无关紧要,只不过那要你per connection per thread就足够了,何必要用IOCP呢。而且发送文件你可以分块分块的发,不用一次全发了,假如不用太多控制的话,直接用Transmitfile得了。
      

  5.   

    sevencat(七猫):
          不知道你对IOCP了解否,可是我看网络上有很多文章都说IOCP的好处就是创建CPU*2个数量的线程,就能够服务成千上万个客户端了。
           如果象你说的那样,微软搞出个IOCP就没有什么意义了。         
      

  6.   

    答:我对IOCP有一定的了解。网上说的cpu*2其实是经验数据,假如你什么事情也不做,只做像科学运算之类的事情,那只用cpu*1是最好的,但不可避免的会碰到其他方面的操作,我印像中只要调用到像WaitSingleObject的时候,这个线程就会被IOCP从运行队列中去掉,同时激活另一个线程。像文件读写(ReadFile这种事情是肯定会调用到WaitSingleObject除非你这个地方也用异步来做。
      

  7.   

    同意临风、七猫的说法,可以考虑再开几个工作线程,或用TransmitFile。
      

  8.   

    1 iocp的工作线程只能用来recv send,不能用来干别的,特别是产生不能调用会阻塞的函数。2 一个完成端口,可以同时传递多个文件,不用一个文件一个完成端口。因为完成端口内部就是多线程处理的,内部会轮流执行关联到完成端口的sock的所有的io操作的。
      假如有100个socket关联到一个完成端口,那么这100个socke是可以轮流传输数据的。  如果你创建多个完成端口,所压榨的并不是cpu,而是你的系统上的其他应用程序的时间。
      比如这台机器上还有一个进程在进行数据库操作,那么如果你创建了3个完成端口,那么后2个完成端口多出来的线程所占用的时间是从你的数据库操作进程抢来的。
     
      所以,对于没有阻塞调用的完成端口的工作线程来说,一个足够了
      如果含有阻塞调用,那么这是在大多数情况下失败的设计。借用宝地问个问题。如果我在一个sock上投递10个recv,那么这10个recv完成并返回的顺序肯定是按照流的顺序的吗?
      

  9.   

    我想如果IOCP是以上这样的一种工作方式,那么开再多的线程也不一定满足需求,未免会出现一些客户端无法及时被处理从而导致超时或者其他问题。IOCP很多用在游戏的开发上,游戏可是有很多客户端,服务器有可能同时收到成百上千个客户端请求,难道要服务器先开好成百上千个请求吗??那还用ICOP模型干么,直接用那些select模型,来个客户端,启动一个线程,perthread--perclient,岂不更好??
      

  10.   

    补充一句,关联了完成端口的socket的,send, recv都是非阻塞函数,内存拷贝函数也是非阻塞函数。非阻塞函数如果用多线程来并发执行,完全没有意义。
      

  11.   

    wd_6532(胜败有常) 大侠:
           如果iocp的工作线程只能用来recv send,不能用来干别的,那么请问,怎么处理客户端的请求??
           就比如客户端送两个数字A和B,送给服务器后,服务器计算A+B,然后把结果返回给客户端。
            如果你说不能在工作线程上做A+B,请问在程序上我在哪里去做A+B ??A+B做完后,我又在哪里发送给客户端?? 
            大家千万别说A+B耗时很短哟,我只是举个简单的例子以便把问题问的清楚。
      

  12.   

    补充一句,关联了完成端口的socket的,send, recv都是非阻塞函数,内存拷贝函数也是非阻塞函数。WRONG!!!
      

  13.   

    wd_6532(胜败有常) 大侠:
           如果iocp的工作线程只能用来recv send,不能用来干别的,那么请问,怎么处理客户端的请求??
           就比如客户端送两个数字A和B,送给服务器后,服务器计算A+B,然后把结果返回给客户端。
            如果你说不能在工作线程上做A+B,请问在程序上我在哪里去做A+B ??A+B做完后,我又在哪里发送给客户端?? 
            大家千万别说A+B耗时很短哟,我只是举个简单的例子以便把问题问的清楚。
    =========================
    1 A+B不是阻塞函数,不会引起cpu的等待,无需要多线程处理你执行1+1 1万次, 一个线程执行,还是多个线程执行效率是一样的,说不定多个线程速度还慢。2 recv之后,把数据放入缓冲队列中,然后由另外一个线程进行数据的处理,比如写库之类的。3 如果你的完成端口的工作线程进行写库操作,那么可能你的socket缓冲区一会儿就慢了,因为socket比数据库io快很多很多。
      

  14.   

    IOCP中,一般GetQueuedCompletionStatus是阻塞的,其余的都是非阻塞的。在工作线程干CUP bound
    的工作不好,做好另开其它线程。
      

  15.   

    wd_6532(胜败有常) 大侠:
           1、我举例的A+B只是为了把问题说得清楚,为了计算A+B而写一个服务器,那是没有意义的。我的目的是说假设A+B需要50妙才能完成,那么如果由工作线程来完成A+B的动作,那么工作线程不就是在这50妙内一直在做A+B了,在这50妙内就无法从IOCP上继续取得队列了,因为工作线程一般是一下这样的: 
                while(true)
                {
                      GetQueuedCompletionStatus (......);
                      .......
                       A+B; //计算A+B,假设需要50妙
                      ......
                 }
    而我只创建了2个工作线程【因为我的CPU=1啊】,如果再有一个客户端到来,那么另外一个工作线程不也是在计算A+B了吗,这不就导致没有空闲的工作线程去服务于继续来的客户端了,只有等其中的一个线程干完A+B后,继续下一轮循环,执行函数GetQueuedCompletionStatus;如果是这样,那么IOCP何以能叫“开启CPU*2个线程,却能够服务于成千上万个客户端请求”?
           2、第二个问题是想问,既然你说IOCP工作线程只用来send,recv,那么A+B的这个动作就不是写在如上的循环里面了,那么请问,是不是要建一个新的线程类【非工作线程类】,在工作线程每接受到一个队列,然后就开启一个这样的线程来处理A+B???如果是这样的法,那么这个线程在计算完A+B后,又怎么样把结果发送给客户端??        其实我的服务器是做帐务处理系统的,客户端提交一些有关帐务数据后,送到服务器端,服务器端再数据库里面登记帐务、帐务借贷处理等,然后再发送返回数据包给客户端,告诉客户端帐务处理的结果等信息。
            帐务处理的过程要对数据库进行操作、计算、写日志等,这个可是一个比较耗时的过程,并不象echo服务器那样快速回应给客户端。
            所以在这种情况下,我是不是要写个“帐务处理线程类”,在IOCP的工作线程GetQueuedCompletionStatus后,开启一个新的“帐务处理线程”对接收到的信息进行处理???如果是这样,处理完的结果又是怎么返回给客户端??难道先提交一个请求给IOCP,再由IOCP发送报文给客户端?还是直接在“帐务处理线程”里面直接调用send函数往客户端发送报文??
      

  16.   

    1:
                  while(true)
                {
                      GetQueuedCompletionStatus (......);
                      .......
                       
                         {
                            PostTheTaskToThreadPool();// A+B; 计算A+B,假设需要50妙,让线程池去做。                      }                  ......
                 }
    2:
      

  17.   

    楼主的问题同我当初没有理解时的想法差不多。
    不过要考虑的是WSASend(WSARecv类似),调用以后并不需要等待完成,这样就有可能你本来一个文件的大小是100KB,比如你切分成2k/块,那么也就是50份,这里假设每次提交的发送请求都一次性送出,而当你每使用WSASend发送(实际上该称为预发送)2k,系统不会立即发送出去,而是WSASend返回立即返回,并且此时会得到一个Error:ERROR_IO_PENDING,然后这个线程的工作基本上就算是完成了,而跳回到GetQueuedCompletionStatus去接受其它的任务,关键是如果有其它连接同步发生请求,或者发送完成了(WSASend所发送出去的2k已经完成,这里假设一次性完成递交工作),所以你可以为他们进行服务,也就是说,你可能前面服务的是A客户,此时得到的就有可能是B客户,而A客户的下一个2K的发送任务,很可能是其它的结程去处理,而不是你自己本身这个结程,这也就是线程池的概念。
      

  18.   

    我发觉很少有人真正明白 IOCP 的线程模型及如何利用
      

  19.   

    我也不是很明白IOCP的线程模型,但是我仅仅利用了IOCP可以管理N多个socket这个特点来做服务器.还有我是通过文件分块来解决楼主的问题把所有传输异步化就能解决问题了,最重要的的是不要阻塞很长时间
      

  20.   

    工作线程是等待系统完成你发文件 传输的任务是交给系统的 完成后通知工作线程(实际工作线程等待) 所以假如搂住
    (问题是,如果处理客户请求的过程很耗时,比如是文件传输服务器ftp,如果TheadA正在服务某个客户端ClientA,ClinetA请求传输好几百兆的数据,那么线程ThreadA就一直在为ClientA服务,说不定好几个小时哟【因为文件有好几百兆啊】,如果另外一个客户ClientB也提交了一个几百兆的文件请求,那么ThreadB为ClinetB服务,估计也是要很长时间)因为传输文件是系统,所以 假如这个时候有新连接 工作线程得到通知 就处理新连接 文件传输完毕 工作线程得到通知 就处理ClientA或ClientB  就算工作线程只有一个线程 处理这些也是没有问题的吧
      

  21.   

    首先要明确的是传输过程当中不管是输入还是输出的缓冲区都是有限的,并不因为你的文件大,socket的缓冲区就会增大,所以一次性投递出去的数据只能是有限的,即使你没有明确地给它分块,系统也会自动拆分,而每传输完一个小块仍然会发出通知,并且这个通知是按队列形式发送出来的,通知消息和线程之间是两个完全不相关系的队列,也就是说如果有一万个连接进来,而有两个线程服务的话,你现在服务的是第一个通知,则发送间隔之后,这个连接的通知,将会被排到10001号,而你再去取的时候,可能另一个线程正在服务第2号通知,所以你再服务的就是第3号通知,而离10001还有相当的时间.对于传输文件,竟然当中,有另外一个传输文件的函数可以用,并且这个传输,只要你一次性提交出去则由系统内部自动完成,而无须干涉.
      

  22.   

    ClinetA请求传输好几百兆的数据,那么线程ThreadA就一直在为ClientA服务
    ==============
    这个理解应该是错误的。1 如果自己分解文件发送,那么每次调用异步的write之后,应用线程并不阻塞,如果100个sock要传输100个文件,你可以轮流在每个sock上传送每个文件的4096字节,而每次write是不会阻塞的(不会阻塞的意思,就是不会让一个线程一直为每个文件的传送服务)2 如果调用异步tranmitfile(也不会阻塞),那么这100M文件的传输是由iocp内部的线程来进行处理的,不会让你的一个线程阻塞的等待到100M数据的传输完毕。3 所谓异步的方法,可以这么理解,如果硬件支持,你调用tranmitfile之后,剩下的工作就不占用系统cpu了,tranmitfile告诉网卡,你给我传送这个文件,那么网卡的cpu会自己从硬盘里读取文件酌情发送,当网卡发送完毕之后,就通知操作系统,那个文件我传送完毕了,那么系统的cpu才开始执行你的完成例程,通知你这个文件已经传输完毕。
      write的过程是一样的,writer之后,如果硬件支持,网卡会不在系统cpu的帮助之下,自己读取内存,自己发送数据。  当然,如果硬件不支持,系统内建的线程会在系统cpu的支持下做这些从存储器到网卡的传输操作。楼主还是自己看书吧,windwos网络编程,或者unix网络编程第一卷。大家跟你这么讲,你也不会明白,就算你明白了,也是一知半解。举例吧,假如你在学线性代数,如果你不看书,只是发贴问,是永远不能活学活用的。有人回答我的问题吗?如果我在一个sock上投递10个recv,那么这10个recv完成并返回的顺序肯定是按照流的顺序的吗?
      

  23.   

    ClinetA请求传输好几百兆的数据,那么线程ThreadA就一直在为ClientA服务
    ==============
    这个理解应该是错误的。1 如果自己分解文件发送,那么每次调用异步的write之后,应用线程并不阻塞,如果100个sock要传输100个文件,你可以轮流在每个sock上传送每个文件的4096字节,而每次write是不会阻塞的(不会阻塞的意思,就是不会让一个线程一直为每个文件的传送服务)2 如果调用异步tranmitfile(也不会阻塞),那么这100M文件的传输是由iocp内部的线程来进行处理的,不会让你的一个线程阻塞的等待到100M数据的传输完毕。3 所谓异步的方法,可以这么理解,如果硬件支持,你调用tranmitfile之后,剩下的工作就不占用系统cpu了,tranmitfile告诉网卡,你给我传送这个文件,那么网卡的cpu会自己从硬盘里读取文件酌情发送,当网卡发送完毕之后,就通知操作系统,那个文件我传送完毕了,那么系统的cpu才开始执行你的完成例程,通知你这个文件已经传输完毕。
      write的过程是一样的,writer之后,如果硬件支持,网卡会不在系统cpu的帮助之下,自己读取内存,自己发送数据。  当然,如果硬件不支持,系统内建的线程会在系统cpu的支持下做这些从存储器到网卡的传输操作。>>TransmitFile也照样占用CPU的资源,只是拆包过程不再需要用户线程甚至是进程进行干涉,TransmitFile并不是告诉网卡去做什么事情,而是交任务与系统底层模块,由底层模块去执行传输任务,网卡没有CPU,即便网卡住成了处理模块,那也不会进行网络传输以外工作的,更不会自己去读文件之类的
    楼主还是自己看书吧,windwos网络编程,或者unix网络编程第一卷。大家跟你这么讲,你也不会明白,就算你明白了,也是一知半解。举例吧,假如你在学线性代数,如果你不看书,只是发贴问,是永远不能活学活用的。有人回答我的问题吗?如果我在一个sock上投递10个recv,那么这10个recv完成并返回的顺序肯定是按照流的顺序的吗?
    >>在同一个sock上面投递10个WSARecv有任何意义吗?是否按顺序得到影响这有什么关系?完成端口支持异步I/O,同时提交WSASend可以理解是往发送缓冲区追加发送数据流,但是WSARecv每一个都是预先发送,而进行等待,即使用户有数据传来,同时也仅只有一个得到响应,并且用户端,还会阻塞在这次传输过程当中(必须等待一个发送成功或失败的信号,UDP例外),所以我实在无法理解这个10个Recv的为何而设想
      

  24.   

    如果我在一个sock上投递10个recv,那么这10个recv完成并返回的顺序肯定是按照流的顺序的吗?IOCP的GetQueuedCompletionStatus是LIFO,而I/O是FIFO
    参考 MSDN   Writing Scalable Applications for Windows NT
    另外你说的TransmitFile不占CPU的说法,在那里可以查到.MSDN上看,在传完后会触发GetQueueCompletionStatus.但没说不占CUP阿?
      

  25.   

    偶也认为投递多个WSASend可以理解,但是投递多个WSARecv没有必要
      

  26.   

    另外你说的TransmitFile不占CPU的说法,在那里可以查到.MSDN上看,在传完后会触发GetQueueCompletionStatus.但没说不占CUP阿?
    ===============================我只是给楼主举一个极端的例子。假如网卡硬件支持,TransmitFile之后,网卡(假如能识别硬盘)自己从硬盘里读取数据发送,而不用操作系统控制cpu从硬盘里读取数据到内存,然后在把数据从内存发给网卡。这只是一个极端的例子,但是这个例子可以很好的解释异步IO的目的。
      

  27.   

    我只是给楼主举一个极端的例子。假如网卡硬件支持,TransmitFile之后,网卡(假如能识别硬盘)自己从硬盘里读取数据发送,而不用操作系统控制cpu从硬盘里读取数据到内存,然后在把数据从内存发给网卡。这只是一个极端的例子,但是这个例子可以很好的解释异步IO的目的。=====================================
    有这样子举例子的吗?如果不懂,则最好沉默,而不是误导.更何况所举的例子再极端,也没有任何一家的系统可能这样子设计?什么叫分工协作?更何况TransmitFile这是实实在在的Windows API,并且网卡也是实实在在已经用了N次的一道硬件设备.不管如何设置,网卡不等同于内存,可以使用DMA技术,内存是可以分配后独占的,但是网卡的工作却远比内存更加复杂,并且在现在来说,更讲求一种异步作业.再者,网络IO存在着不可控性,所以任何一个异常的出来,都需要相应的机制配合处理,而网卡不能独裁决定.
    另外,不管从任何一个方便都无法去解释异步IO,所谓的异步I/O,实际上是指的I和O异步作业,而实际并不是多次Input或者Output异步作业.而让系统独立地传输一个文件,又如何体现了异步IO的机制呢?这里面仅仅只能说明了TransmitFile的一个步异线程作业,而不是I/O.
      

  28.   

    完成端口的工作线程只能为网络数据服务,对于别的业务上的逻辑不能使用这个线程来做.你可以把接收到的数据包放在一个消息队列中.然后使用线程池来处理数据包.
    由于有不同的业务,你可以使用分流,创建不同的消息队列.线程池这样来增加你的处理能力.对于网络数据通信这一块,想来使用完成端口也行了.让这一些网络的事件完全让完成端口来做.前几天看了一下传奇的服务器代码.他就是这样做的.如果有网络事件过来之时,只有上线与下线的这样的数据是通过完成端口的工作线程来做.如走路与聊天,打人这样的消息都只是做为一个指令被排在每一个Play对象的队列中.在全局有一个单线程在做时间片循环来处理所有的用户的消息.这就是所谓的网络事件驱动.还有线程驱动的不同.反正要让业务与数据分开才能让你的服务器高效起来.
      

  29.   

    FTP的话,你的IOCP Thread只要把当时投递给你的数据处理完了就可以返回了,具体的,可能是一个memcpy,更可能仅仅是一个指针 += n,你觉得这样的操作需要多少CPU时间?
    如果你的程序写的没错,2个小时的FTP应用确实需要2个小时以后再完成,但是你用任务管理器会发现你的进程实际总共只占用了0.00n秒的CPU时间。
      

  30.   

    有这样子举例子的吗?如果不懂,则最好沉默,而不是误导.更何况所举的例子再极端,也没有任何一家的系统可能这样子设计?什么叫分工协作?更何况TransmitFile这是实实在在的Windows API,并且网卡也是实实在在已经用了N次的一道硬件设备.不管如何设置,网卡不等同于内存,可以使用DMA技术,内存是可以分配后独占的,但是网卡的工作却远比内存更加复杂,并且在现在来说,更讲求一种异步作业.再者,网络IO存在着不可控性,所以任何一个异常的出来,都需要相应的机制配合处理,而网卡不能独裁决定.
    另外,不管从任何一个方便都无法去解释异步IO,所谓的异步I/O,实际上是指的I和O异步作业,而实际并不是多次Input或者Output异步作业.而让系统独立地传输一个文件,又如何体现了异步IO的机制呢?这里面仅仅只能说明了TransmitFile的一个步异线程作业,而不是I/O.
    =====================================================不太明白这么多行讲了什么意思。异步IO的意思,不就是我的应用只要通知系统或者硬件去进行一项IO操作,通知一下我就可以做我自己的事情了,我的线程不用挂起去等待IO的完成,等IO完成了,硬件会通知系统或者系统会通知应用线程。就是这样啊。关于异步IO,我的理解有什么错误?
      

  31.   

    不太明白这么多行讲了什么意思。异步IO的意思,不就是我的应用只要通知系统或者硬件去进行一项IO操作,通知一下我就可以做我自己的事情了,我的线程不用挂起去等待IO的完成,等IO完成了,硬件会通知系统或者系统会通知应用线程。就是这样啊。关于异步IO,我的理解有什么错误?
    =================================
    我并没有说你所举例的不是一种异步机制,仅仅只是,你的举例都是不可行的,又如何能用来说明一个问题?即便只是一个未决的设想,也需要考虑一个可行性,如此才有说服力.
    你不能说两人同向走一种路,前面的那一个队长带队发出一批车,就与你后面发的车是异步.交通也有个流量问题,可能前一个队长带的车子数量多,那么你就肯定会受其影响,甚至可能他的车队还没发完车,你就已经发车了,能说是这一种异步吗?另一种情况,现在的道路都是双向分离的,你大A点出发往B点,另一个人从B点出发往A点,不论如何,你们都不受对方的行车所影响(违规除外),这种才称之为异步.
      

  32.   

    菜鸟问题引起高手的论战了,都不知道聊到哪里了。 ^^你的I阿O阿,异步啊,DMA阿,再牛,你能牛到不占系统总线?硬盘不够可以RAID,可以SCSI,CPU不够可以多个,总线不够快呢?CPU的频率是多少,总线的频率是多少?我一直没有理解的问题,始终觉得PC那个单纯的总线才是真正的瓶颈,不明白为何很少有人关注这个。
      

  33.   

    异步IO的意思,不就是我的应用只要通知系统或者硬件去进行一项IO操作,通知一下我就可以做我自己的事情了,我的线程不用挂起去等待IO的完成,等IO完成了,硬件会通知系统或者系统会通知应用线程。
    ========================>同意这个说法
      

  34.   

    好像跑题了,越到后面越和IOCP没关系了,呵呵.
      

  35.   

    使用异步模型吧,
    http://bbs.helloit.info/blog/article.asp?id=135
      

  36.   

    楼主理解错误,即使传输再大的文件,也不是一次非要把所有数据传送完成啊,也是得
    每次传输一部分啊。这可以是异步的。
    另外更正你一个错误的理解就是FTP有两种不同类型的连接,一种是命令连接
    (command connection),另一种是数据连接,命令连接收到上传下载文件的命令时,
    会另开一个连接,这些操作都是异步的,不是这个连接就一定要等在那里(专业术语:阻塞)
    每个客户一个线程是不可能的,那样线程切换的系统开销得不偿失,也没有用到异步的概念
      

  37.   

    楼主只要理解:IOCP是异步IO的一种模型,要处理大量的客户服务请求,只有异步才能处理
      

  38.   

    这个问题也需要争论哦,什么年代了,IOCP和服务程序编写早就是熟得不能再熟的技术了。我说两句吧。说得不对,大家批评!!讨论这些问题时,不要只注意IO啊,线程啦,效率啦,连接数啦这些东西,最重要的你们估计都忘记了:线程载体!!
    1。IOCP一般只用于“响应socket的recv消息”,发送数据时,其线程载体未必是IOCP线程,建议使用其它线程池的线程(IOCP本质上就是1个线程池,速度稍微快一点而已)来处理业务逻辑;2。IOCP照样可用于“长连接socket”,无论是“大数量的并发访问”还是“长时间的事务处理”,只要在收到数据之后,把数据投递到另外1个线程池里处理,而IOCP就立即返回了,不会造成任何socket层面的延迟和阻塞(即:转换处理事务的线程载体)。本人在win2k下测试过最高4000个并发连接(P2-350,28M);3。我在项目里写的服务器,用3个线程池:第1线程池是IOCP,处理recv消息;第2线程池是普通线程池,处理程序事务;第3线程池是普通线程池,用来send网络数据;4。多写程序多研究,少抄书本少瞎说。实践出真知;
      

  39.   

    版主怎么回事啊???这么水的贴子也放在CSDN主页热贴上?
      

  40.   

    所谓完成端口 就是在系统底层完成发送任务的时候通知你的应用程序,即便发送很大的数据块
    WSASend也会马上返回 在该数据块真正发送完成之后 会有一个县程的GetQueuedCompletionStatus返回,来通知你发送结束 你就可以进行其他处理了
      

  41.   

    1. 如果是这样,那么IOCP何以能叫“开启CPU*2个线程,却能够服务于成千上万个客户端请求”?
    --------------------------------------------------------------------------------
    这就相当于huangbeyond(校园人渣) 中的“第1线程池是IOCP,处理recv消息”.2. 那么请问,是不是要建一个新的线程类【非工作线程类】,在工作线程每接受到一个队列,然后就开启一个这样的线程来处理A+B???
    --------------------------------------------------------------------------------
    这就相当于huangbeyond(校园人渣) 中的"第2线程池是普通线程池,处理程序事务"在Receive后,是需要你再建立一个数据处理队列的,其中你可以包含该业务的client的socket的.这样你处理完数据可以根据这个socket句柄发送回该client端的.
    如果是这样的法,那么这个线程在计算完A+B后,又怎么样把结果发送给客户端??
    ---------------------------------------------------------------------------------第3这就相当于huangbeyond(校园人渣) 中的"第3线程池是普通线程池,用来send网络数据;"
      

  42.   

    to huangbeyond(校园人渣) ( ) 信誉:105 1。IOCP一般只用于“响应socket的recv消息”,发送数据时,其线程载体未必是IOCP线程,建议使用其它线程池的线程(IOCP本质上就是1个线程池,速度稍微快一点而已)来处理业务逻辑;2。IOCP照样可用于“长连接socket”,无论是“大数量的并发访问”还是“长时间的事务处理”,只要在收到数据之后,把数据投递到另外1个线程池里处理,而IOCP就立即返回了,不会造成任何socket层面的延迟和阻塞(即:转换处理事务的线程载体)。本人在win2k下测试过最高4000个并发连接(P2-350,28M);3。我在项目里写的服务器,用3个线程池:第1线程池是IOCP,处理recv消息;第2线程池是普通线程池,处理程序事务;第3线程池是普通线程池,用来send网络数据;4。多写程序多研究,少抄书本少瞎说。实践出真知;--------------
    我一般把你第三个线程池和第一个重合起来,这样效率会更高。
      

  43.   

    我来个总结:
    1,我会创建cpu*4的线程数处理,res,and send.
    2.我会用cpu*8的线程数处理所有事务。同时post cpu*4个accept,这样同时最大的并行accept就会是cpu*4;
    对于每个accpte的clinet post 1 read
    接收的情况:
    当clienta收到一个完成通知的时候,处理buff,把结果(list)放到client结点中,post event(注意给clienta ->addref())给2,2派出一个idle thread to 处理clienta ,clienta->release().
    N个client的时候,情况类是。发送情况。
    在2中业务和暴风雨一样复杂,而对于每个结点来说,都是single thread的,如果2没有idle的线程,对于和结点clienta一样的其他结点来说,他们的包结果来不级处理的时候,会list到自己的结点上。直到2有idle的线程来处理。但1中的线程还在快乐的接收的自己数据。
    当2中某个thread的接受到一个命的时候,比如要发送一个数据,2 post event to 1,1从clienta中的list取出一个待发包,post write.这样可以避免多个线程对同一个socket post wirte,大家都知道如果一个socket 在pending状态时,不能对同一个overlay发起两个post write.我们之所以用一个Overlay而不用多个,是为了程序着想,不需要太复杂。因为对于同一个包,有可能需要post 多次。这样,我们可以通过结点的记录上次发送了多少byte.从而正确的从上次的offsize post.业务处理上:
    我一般不会把分析包的fuction放在io处理线程中,也就是iocp中,我会暴路一个接口类,比如一个pure class.这样做,可以很好的把类分离,并且可以应用到不同的应用中。
    从上面的分析可以看出,真正的执行者肯定在2中,当2有一个包分析完成的时候,我会post一个event给2,也就是自己发事件给自己。让2分配出另一个线程来处理业务,而原来的线程可以继续分析包。2->2的情况,也不是一概而论,看具体的业务。但这样做,就可以比较高效了。
      

  44.   

    我现在的处理方式上面,与楼上的有点不一样.线程数量上面我不会固定,也就是不受CPU的多少而限制.但是会给出一个同步运行线程数参考值.比如CPU*2.但是实际运作过程当中会由于有多个网络事件到来,而可能这个值会被耗光,也就是在某个时间里没有线程处于GetQueuedCompletionStatue阻赛来处理下一个网络事件,此时我就会考虑再添加一个例外线程,来做等待.由于多出了一个例外线程,所以可能已经超过允许同时运行的线程数量参考值,则哪一个线程完成任务后先做值检测,若超出则看是处于阻塞状态的线程数是否达到两个,若是则自行结束(这时候会带一个麻烦事情就是,该线程的退出会引发由其发出的I/O请求被取消,也会有一个网络事件).
    不过我发送时是直接使用WSASend拉交,也就是说可能会有两个线程同时工作于一个连接之上.只是当有执行WSASend时,Sending计数加1,而下一轮需要发送时,先检测Sending计数.如果有Sending,则直接把数据包附加到Sending队列,如此也可以保证数据的顺序性,同时不需要PostQueuedCompletionStatus,少一个切换过程,并且实现真正意义上的重叠IO,对于处理发送完成事件的线程,则可以一直发送WSASend到没有待发数据为止,每一次完成通知则扣减一个完成计数,每提交一次WSASend则增加一个计数.
    由于有多个线程引用一个连接的上下文信息,如果在删除时直接删除,则会报错,所以在需要设置删除前,先置删除标识,所有线程遇到该标识将不再发送WSASend/WSARecv,另由一个检测线程来对没有(发送和接收)计数的数据进行清理(记得closesocket先,以阻止所有后来的网络事件,在下一次检测过程当中清理为其分配的资源,并删除).
    检测线程主要有两项工作,一是清理垃圾,二是针对不良连接,也就是在一段时间内没有任何I/O操作的连接进行清理,也就是说如果是自己的客户端则最好是在没有数据交互的情况下发送时脉信息,对于部分需要验证的服务,也可以在此对超时未进行身份验证的连接清理掉.
      

  45.   

    线程不是提高程序运行能力的方法,只是用来减少无谓的等待时间而已。wwwllg(wwwllg)说得应该是自己实践体会中的点滴吧,不是什么总结或规律,自然对他人无多意义
      

  46.   

    我不光是写给你看,是写给需要的人看。
    我测试过3k多人的客户同时直播,双cpu的机器cpu在70%左右,其实这里主要引响cpu的是代宽而不是我的处理流程。用第三个线程池去主动投递会严重引响性能。同样的条件,当500人在线时就会cpu非线性增加。内存的合理利用对cpu的引响也很强烈。