• 实现高性能稳定的socket tcp通讯经验分享


        其实在.net socket编写高性能稳定方面的资料真的比较少,一个实质性的测试数据结果对比就更少了.我们可以从http://msdn.microsoft.com/zh-cn/magazine/cc163356.aspx看到MS说net 2.0 sp1后的socket通讯能力非常强劲,可以同时挂起6W个IO(可以简单地认为可以在一秒内send+receive可以达到6W或更高),但要找这个数据的测试似乎很难.但在一篇MS关于WCF的性能测试中基于tcp部署的性能在一台4路服务器中可以达到这个量(http://msdn.microsoft.com/en-us/library/bb310550.aspx).那WCF可以达到那基于c# socket实现达到这样的IO处理能力应该完成没问题.经常一段时间的努力即使在一台core e4300 5年前的PC上完全胜任每秒6W IO的处理能力,还包括数据接收,协议分析对像序列化写入.

    以下是一些经验总结:

    Buffer Pool

    这个相信不用说,MSDN上也介绍这种用法.但如何分配这个buffer大小呢?我们一般会一条消息用一个buffer,这个时候我们就很难分配了,不得不按最大消息长度来定义buffer长度,这样做从内存分配上来说是极其不合理的.不过现在内存多不用计较(也许).但还存在一种问题就是send的时候一般针对buffer的,当消息小的时候就不得不按消息的数量来操作IO,如果buffer的灵活性更好如小的消息可以多个写入一个buffer,大的消息可以写入几个buffer.这样即能达到内存使用合理.也能控制最少的IO处理最多的信息达到更好的性能.

    SocketAsyncEventArgs池需要吗?

    这个MSDN上也有介绍这种用法,但就存在一个如何分配的问题,连接产生的时候分配,连接断开的时候回收?如果是这个SAEA怎样分配buffer大小(别轻易地使用SetBuffer(byte[],int,int)方法);不得不面对以上Buffer说的问题.所以SEAE和Buffer Pool一样大小来分配池结合使用,用的时候拿用完回收到池. 其实SEAE最好是和BUFFER整合在一起,这样做的好处就是在高并发的时候可以节省大量的byte[] Copy.

    队列的使用

      队列的使用就是更好控制线程处理数据,既然一个线程就能更好地完成工作,可必要用更多的线程去做呢.记住用最少的线程完成最多的事情.

    在运行期内你能做到最少化内存分配吗?

      你能让一些getByes方法不产生new byte[]吗?好好看下MSDN相关对像方法看有什么途径来达到这种效果.

    不于过于自信多用些分析工具

      也许你有着很多年的经验,也用一些计时器来衡量过代码的执行行性能.但有时候你真的很难发现原来性能并不存在于你测的地方.不要只关注于代码的CPU执行时间,别忘了.NET下还有一个巨头GC.用性能分析工具分析代码的执行时间同时,不要忘了分析一下代码在某些情况下的内存分配情况.VS2010就提供了这些方便的分析工具.

    以下是这段时间优化的测试情况

    测试结果一:

    1K连接分别获取一个对像和一个列表对像

    单一对像信息

    class GetResponse : IMessage
        {
            public User User;
    
            public void Save(BufferWriter writer)
          
        }
        class User : IMessage
        {
            public string Name;
            public string EMail;
            public string City;
            public string Counrty;
            public void Save(BufferWriter writer)
            {
                writer.Write(Name);
                writer.Write(EMail);
                writer.Write(City);
                writer.Write(Counrty);
            }
            public void Load(BufferReader reader)
            {
                Name = reader.ReadString();
                EMail = reader.ReadString();
                City = reader.ReadString();
                Counrty = reader.ReadString();
            }
        }

    列表对像信息(5条)

    class Response : IMessage
        {
            private IList<Order> mOrders = new List<Order>();
            public IList<Order> Orders
            {
                get
                {
                    return mOrders;
                }
            }
        }
        class Order : IMessage
        {
            public int OrderID;
            public string CustomerID;
            public int EmployeeID;
            public long OrderDate;
            public long RequiredDate;
            public string ShipName;
            public string ShipAddress;
            public string ShipCity;
            public string ShipRegion;
            public string ShipPostalCode;
            public string ShipCountry;
            public void Save(BufferWriter writer)
            {
                writer.Write(OrderID);
                writer.Write(CustomerID);
                writer.Write(EmployeeID);
                writer.Write(OrderDate);
                writer.Write(RequiredDate);
                writer.Write(ShipName);
                writer.Write(ShipAddress);
                writer.Write(ShipCity);
                writer.Write(ShipRegion);
                writer.Write(ShipPostalCode);
                writer.Write(ShipCountry);
            }
            public void Load(BufferReader reader)
            {
                OrderID = reader.ReadInt32();
                CustomerID = reader.ReadString();
                EmployeeID = reader.ReadInt32();
                OrderDate = reader.ReadInt64();
                RequiredDate = reader.ReadInt64();
                ShipName = reader.ReadString();
                ShipAddress = reader.ReadString();
                ShipCity = reader.ReadString();
                ShipRegion = reader.ReadString();
                ShipPostalCode = reader.ReadString();
                ShipCountry = reader.ReadString();
            }
        }

    测试结果

    测试结果2:

    由于局域网带宽限制,所以只能测试2K和3K连接下的单一对象获取

    除了以上测试结果外,还进行了同场景500物体状态变更广播,在core e4300也完全能胜任,每秒转发50W的消息量.每个client的消息延时在100ms以内.

    同场景物体广播测试程序:http://www.henryfan.net/file.axd?file=2012%2f3%2fBroadcastTest.rar (想测试效果请分开电脑运行,如果你的网络是100mb的话最大只能运行5个client,如果服务器的cpu低于core e4300也有可能支持不了500同屏)

    访问Beetlex的Github
  • 相关阅读:
    十月八日学习报告
    十月七日学习报告
    十月六日学习报告
    十月五日学习报告
    十月三日学习报告
    为二级域名注册ssl证书,并强制使用https对http进行跳转
    google protobuf 数据类型_理解Protobuf数据格式解析
    JaveScript 中使用 XSLT转换XML文档
    移动端拖拽
    Web容器_Web服务器及常见的Web容器有哪些?
  • 原文地址:https://www.cnblogs.com/smark/p/2413188.html
Copyright © 2020-2023  润新知