大家好,开发服务端程序时,性能一定是大家非常关注的.我也看过许多关于数据接收的观点,大致有两种立场:1、投递多个接收操作(WSARecv),充分发挥IOCP性能,但是需要自己组织IO顺序,而且一旦连接量过大,会消耗大量未分页内存,可能会导致性能急剧下降。2、一个连接投递一个接收,并且把接收长度置0,仅仅起数据到达通知作用,有数据立即使用简单的非阻塞接收数据,直到接收返回为WSAENOBUFS(无数据可接收),再重新投递0长度的接收操作,这样可以大量节省未分页的使用。不知道大家有何见解?

解决方案 »

  1.   


    有必要同一个连接投递多个接收操作吗?WSARecv()投递一个完成后,继续投递另一个就是.如果第一个WSARecv()是pending,后面你再投递N个,一样是pending的,这明显是画蛇添足.
      

  2.   

    虽然都是pending,但是一旦有数据到达,可以非常快速地接收数据(其实就是快速填充缓冲),肯定效率高许多.
      

  3.   


    你能知道有多少数据到达吗?如果一个WSARecv()的缓冲已经足够接收到那些数据,你后面的WSARecv()不是一样pending吗?如果有很多很多数据同时到达,一个WSARecv()缓冲接不完,要三个WSARecv()才能接收完,多次投递WSARecv()自然可以达到加速,不过你可想过很个投递都使用4的N倍的非分页内存,系统非分页内存一旦被用光,那不是你的程序无法响应任何网络操作这么简单,最好的都会是整个系统无法响应任何网络请求,最坏的结果是系统蓝屏.32位系统中非分页内存都是有限的.我的观点是,现时的电脑的硬件配置已经足够的高了,多投递多个WSARecv()实现的那点加速的效果(加速效果只有是单个WSARecv()远不足以接收完数据的情况),抵消不了非分页内存大量开销有可能带来的副作用.不过,如果你能确定你程序最大量地投递WSARecv()也不会令系统崩溃,而单个WSARecv()远不足以接收完数据,那么多个WSARecv()投递,也是一个好的方案.
      

  4.   


    对于第二种情况,我也并不认为是什么好方法.如果接收长度置0,那么已经失去了重叠IO的主要功能了,这种接收和一般的使用系统消息通知去接收数据没有太大分别.还有就是,如果设置接收为0,那么返回的通知,接收到的数据也为0.但在一般IOCP程序中,WSARecv()接收到数据为0,可以认为是某种错误,可以断开的了.例如:
    while(TRUE)
     {
     bSuccess = GetQueuedCompletionStatus(CompetionPort,&BytesTransferred,(LPDWORD)&IOHandle,(LPOVERLAPPED*)&IOData,INFINITE);   if (!bSuccess || (bSuccess && 0 == BytesTransferred))
             {
                 这里进行断开这个连接的操作
             } 
             ....
             ....
             ....
             ....
    }如果要实现第二种方法,那么0 == BytesTransferred就不可能作为一种错误的判断,那么程序运行时有可能有些应该要断开的连接会错过了.将接收缓冲置0的方法只是一个折衷的方法,一般只是在投递过大量,不能确定系统是否能支持这么大量的投递令非分页内存用尽时暂时使用的一个折衷方法.<<Network Programming For Microsoft Windows,2th Edition>>中有介绍过这种方法,不过已经做了说明,这个只是为了处理更多连接,适用于一些要处理大量连接,但发送或接收数据是很小以及数据实时性不高的服务器中,例如IM服务器等.IM服务器数据传输是很低的,以QQ为例,如果你不说话,只是挂着,有可能10多秒才有个几秒心跳包的数据传输,那么使用这种置0的方法很是适用,因为大部分用户都不会是每秒都有数据传输的.但如果这种方法用于实时数据很高的服务器中,那么就有很多问题出现.
      

  5.   

    首先感谢WinEggDrop的分析,是的,服务端开发看应用于什么场合,针对不同环境要求有不同的侧重点,要么快速反应,要么海量连接.看下面的还有什么建议.