我在书上看到的所谓的重叠I/O模型就是在WSARecv之后,调用WSAWaitForMultipleEvents等待事件信号,当recv得到数据即事件有信号了,接下来可以操作数据,这个效率比select高很多么?WSAWaitForMultipleEvents的意义也不大,WaitForSingleObject就行了,因为如果一个socket的操作很费时的话,while循环就会停住一段时间,从而影响另一个socket的操作,同select,select中传入一个socket的集合意义也不大,一个socket的操作费时同样会影响另一个socket。我看到的socket之间不会相互影响的基本都是accept一个socket就为这个socket开一个线程,这样看起来似乎不好,但网络普遍都是这种代码。有没有一种方法不需要为每个连接的socket开线程(可以开线程,但要有上限,但不影响大量的socket连接),同时又能让socket之间的操作互不影响呢?
或者我理解的重叠I/O模型有错的话,真正的重叠I/O模型怎么是实现同时同多个客户端交互,但相互之间又互不影响呢?我也看过完成端口和完成例程的原理,但我不知道怎么让耗时操作和非耗时操作分离,如果我只开4个线程,那么有5个人同时在下载服务器上一个较大的文件,那么不是总有一个人要等么?如果我的理解不对,请高手详细说明下。
有没有在大型网站或者大型交互式软件或者网游之类公司工作过的大牛?
告诉我,现实情况下,socket服务器究竟怎么样设计,性能才能最高?

解决方案 »

  1.   

    多线程 + 队列 + select  检测状态进行各种回调。不过有上限 FD_SETSIZE
    IO COMPLETION PORTS 上次跟大牛聊这个,被喷过时了。。我吐
      

  2.   

    楼主太多概念没搞清楚,我只能大概说一下,具体还要你自己努力。
    选择模型是轮询的,它只能得到哪个套接字可读可写,具体还要你去recv和send
    异步IO(比如你这里的重叠IO)不考虑套接字的可读可写性,直接WSARecv和WSASend,然后等待操作结束,等待应该是在线程中,等待不耗资源,那么其它线程就可以从容的做其它的事(有资源)。
    比如你要发送1M的数据,select模型你要不停的select,不停的写,直接写完,异步IO一次WSASend投递就结束了(一般来说),直接等结果就行了。网络编程中,不要涉及业务逻辑,收到数据直接扔缓存,业务线程再从缓存里取,网络编程中,只有数据的读写(更专业一点就是内核与用户之间的数据拷贝)以及加解一些锁(队列操作)。所以你所谓的耗时操作是不存在的。一个套接字一个线程这种往往出现在例程中,这样简单(其中所使用的套接字往往是阻塞的,开线程以免影响其它套接字操作,否则需要用非阻塞,编程就麻烦了),实际应用中不可能是这样的。在一个套接字上,只投递1个读和0个或者1个写,就做到了各个套接字互不影响了。
    注意,大型服务端的任务是:保证各个客户端不是太慢的得到服务,而不是快速的服务某一个客户端,一定要有这个概念。一定要防止某些客户端饥饿。
      

  3.   


       感谢yang79tao的回答,很专业,最近几天我看了很多这方面的资料,理解又深了一些,WSASend和WSARecv我没怎么用过,你说只要一次投递,然后等待结果,但WSARecv和WSASend不是根据WSABUF的长度来读写固定长度的么,这个值可以超过系统缓冲区的大小8K?如果我需要分开的读呢?比如要先读一个http头部,再读内容,那么还是只要一次投递么?
       你说“所谓的耗时操作是不存在的”这个能再给我详细说明一下么,传输的文件很大呢?有复杂的公式计算过程呢?
      

  4.   

    读的话,投递多少次你无法控制,反正你投递一次读,等待返回,再投递一次读,一直重复这个死循环即可。
    另外,读的情况下,不是说你的缓存有多大,就要读多大,像你说的这样,那如果内核缓存中只有1个字节,你用2个字节的缓存去读,岂不是永远读不到了(如果没有后续数据的话)。写的话,不管是阻塞还是非阻塞套接字,也不管是否是异步IO,都没有规定你传入的buffer最长必须小于多长,理论上是任意长。耗时操作不存在,指的是在网络编程中,只做内存拷贝,不做业务,业务由另外的线程来做,不要在数据收发线程里面做。这就要使用缓存来解决,如果你能设计成我说的样子,即读写线程只做内存拷贝,那么读写线程不会很忙,不会出现你说的处理这个套接字影响哪个套接字的情况(当然,绝对不影响是不可能的),我是要告诉你,一定要用WSAWaitForMultipleEvents。