现在的位置: 首页 > 综合 > 正文

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

2011年12月14日 ⁄ 综合 ⁄ 共 3077字 ⁄ 字号 评论关闭

    其实在.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同屏)

抱歉!评论已关闭.