延时拼包机制让c# socket实现海量数据包广播吞吐

    之前已经简单的测试了c# socket的数据吞吐处理能力,结果虽然比较理想;但以这样的数据包处理量在某些场景下是远远不够用的,在某些应用场景中每秒要处理的数据包不是1,2W个可能几W,上10W或更多的数据包吞吐。在一个游戏场景中同场景存在100用户,每个用户的变更都会通知其他199的用户,如果每个用户平均每秒变更3次,那服务端每秒接收转发的数据包就是100x100x3=3w个。如果是200个用户同场景,那所每秒所面对的处理包会是200x200x3=12W个,想c# socket提供这么密集的IO处理是不太可能的事情,即使是可以那也要很不错的硬件支撑。

    从软件上去解决这问题那只能选择减少IO操作,之前的测试表明SendAsync这相的IO操作是非常损耗资源。既然问题已经知道发生在什么地方,我们可以采用减少SendAsync又不影响交互性来达到这一点。大家知道网络访问存在一个延时的系数,通过在可接受的延时区间可以把发送的A的N个数据包打包到一个buffer里,然后进行一次SendAsync操作,原本在这一时间段时有100个消息包发给A,那可以打包成一个这样SendAsync的操作就可以从原来的100次变成一次;那些这节省是相当可观的,当然这个设计尽可能根据当前调度情况来确定,调度空闲的情况下不合拼,调度存在压力的时候进行一个合拼处理。

   以下是针对这个设计的测试结果:

测试硬件:

server:Core2 4300 1.8G 2G win2003

client1:Core i7 Q740 1.7G 4G win764

client2:P4 2.4G 1G WIN2003

测试逻辑:

每个client程序开启50个连接,每个连接秒产生3次座标变化告诉服务端,由服务端专发给其他client.

定期为每个client发送ping包,检测服务器处理和回发的延时时间。

数据结构:

public class ChangePostion:IMessage
    {
        public int X
        {
            get;
            set;
        }
        public int Y
        {
            get;
            set;
        }
        public string ID
        {
            get;
            set;
        }

        public void Save(BufferWriter writer)
        {
            writer.Write(X);
            writer.Write(Y);
            writer.WriteBlock(ID);
        }

        public void Load(BufferReader reader)
        {
            X = reader.ReadInt32();
            Y = reader.ReadInt32();
            ID = reader.ReadBlock();
        }
        private static Random ran = new Random();
        public static ChangePostion GetPoint()
        {
            ChangePostion cp = new ChangePostion();
            cp.X = ran.Next(1, 399);
            cp.Y = ran.Next(1, 399);
            return cp;
        }
    }
    public class Ping : IMessage
    {
        public string ID
        {
            get;
            set;
        }
        public DateTime Ticks
        {
            get;
            set;
        }

        public void Save(BufferWriter writer)
        {
            writer.WriteBlock(ID);
            
        }

        public void Load(BufferReader reader)
        {
            ID = reader.ReadBlock();
        }
    }

100人同场景测试

 服务端程序情况:

 client情况

测试情况来看每个client每秒接收1.6w个数据包,两个client接收大概3.2W个数据包,服务端的下行带宽是2MB/秒,每秒处理3.2W对象写入缓冲发送。

200人同场景测试

 服务器端情况

客户端情况

测试情况来看每个client每秒接收3.2w个数据包,4个client接收大概13W个数据包,服务端的下行带宽是8MB/秒,每秒处理13W对象写入缓冲发送

注意

当使用了拼包的时候就要考虑一下Socket.NoDelay是否需要开启,还有client的ReceiveBufferSize是否需要加大,在测试过程中当存在大量数据包接收的时候有个别client连接接收到的数据不正常,之于这个问题是.net的内置缓冲问题还是程序设计上的缺陷还在追查中(查明原因后会编写文章讲述问题情况)。

下载测试程序

BeetleTest20111127.rar (935.91 kb)

跑测试程序最好把client分布在不同机器上

 通过上面的测试可以让想用C# Socket做应用的朋友更进一步了解它的处理能力到底怎样。对于想要源码的朋友就不需要问了,对于些问题的分析可以访问:www.henryfan.net

 

 

 

posted @ 2011-11-28 10:17  beetlex  阅读(6850)  评论(20编辑  收藏  举报