详解通过.NET缓存提高TCP传输速度

开发 后端
在这里我们将讨论的是通过.NET缓存提高TCP传输速度,希望对大家了解.NET机制有所帮助。

在这里我们将介绍的是通过.NET缓存提高TCP传输速度,这也是提高网络性能的方法,希望对大家有所帮助。

.NET提供了一个NetworkStream 用于TCP 的读写,实际使用时发现直接操作效率很低,哪怕把TCP 的发送缓存和接受缓存设置很大也没有太大提高。后来在对 NetworkStream 读写前设置了缓存,性能一下子提高了很多。

从实际测试结果看设置自己的写缓存,对性能的提升最为显著。我分析了一下,其原因很可能是在向NetworkStream 序列化对象时,序列化程序调用了大量的Write 方法向NetworkStream写入数据,每次向NetworkStream写入数据,数据被首先写入TCP的发送缓存,并且由调用线程设置一个信号通知.Net framework 内部的TCP线程发送缓冲区中已经有数据,TCP线程被激活并读取发送缓冲区中的数据,组包并向网卡写入数据。频繁的调用 NetworkStream.Write 写入小块数据将导致调用线程和TCP线程反复切换,并大量触发网卡中断,导致发送效率低下。如果我们在发送前将数据缓存并按较大的数据块发送给TCP线程,则大大减少线程切换和网卡中断数量,从而大大提高传输效率。

问题到这里还没有结束,我们发送的对象往往较大,如果我们将发送对象全部序列化到buffer中再发送,那么势必占用大量内存,实际上我们无法忍受这种对内存无限制申请的行为,试想一个1G大小的对象,我们在发送前为它另外再开辟1个G的内存来缓存,对于系统来说简直是无法忍受。由于我们用.net 发送数据,我们在发送时需要将对象序列化到流中,而不能像 C/C++那样直接通过指针来读取数据(当然你也可以用unsafe代码,但这种方式会带来其他问题,而且并不为大家所推荐),所以我们需要开发一个专门用 TCP 发送缓存的流来处理读写前的缓存。为此我开发了一个 TcpCacheStream 类,这个类被用在读写 NetworkStream 前先进行缓存。

调用方法很简单

发送过程  

  1. object msg;  
  2. //初始化 msg 过程省略  
  3. System.Net.Sockets.NetworkStream _ClientStream;  
  4. //初始化 _ClientStream 过程省略  
  5.    
  6. //创建TcpCacheStream   
  7. TcpCacheStream tcpStream = new TcpCacheStream(_ClientStream);  
  8.    
  9. //二进制序列化 msg 对象到 TcpCacheStream   
  10. IFormatter formatter = new BinaryFormatter();  
  11. formatter.Serialize(tcpStream, msg);  
  12.    
  13. //将缓存中最后一包的数据发送出去  
  14. tcpStream.Flush(); 

接收过程

  1. System.Net.Sockets.NetworkStream _ClientStream;  
  2. //初始化 _ClientStream 过程省略  
  3.    
  4. //创建TcpCacheStream   
  5. TcpCacheStream tcpStream = new TcpCacheStream(_ClientStream);  
  6.    
  7. //从 TcpCacheStream 二进制反序列化  
  8. IFormatter formatter = new BinaryFormatter();  
  9. objcet result = formatter.Deserialize(tcpStream); 

TcpCacheStream 类为调用者封装了缓存的过程,这个缓存过程实际并不复杂,发送时数据先写入TcpCacheStream的buf中,当buf满后才向NetworkStream 写入数据,否则只缓存。由于最后一包不能保证正好填满buf,我们在写入数据后一定要调用 Flush 方法,将所有数据都发送出去。接收的过程反过来,如果buf中没有数据,就先将数据读入到buf中,然后再COPY给调用者,如果已经有数据则直接COPY给调用者。

TcpCacheStream 的代码如下:

  1. [Serializable]  
  2.     public class TcpCacheStream : Stream  
  3.     {  
  4.         #region Private fields  
  5.         const int BUF_SIZE = 4096;  
  6.         private byte[] _Buf = new byte[BUF_SIZE];  
  7.          private MemoryStream _CacheStream = new MemoryStream(BUF_SIZE);  
  8.         private NetworkStream _NetworkStream;  
  9.          private int _BufLen = 0;  
  10.         #endregion  
  11.         #region Private properties  
  12.         private MemoryStream CacheStream  
  13.         {  
  14.             get 
  15.             {  
  16.                 return _CacheStream;  
  17.             }  
  18.         }  
  19.    
  20.         #endregion  
  21.        #region Public properties  
  22.         ///   
  23.         /// get or set the Network Stream  
  24.         ///   
  25.         public NetworkStream NetworkStream  
  26.         {  
  27.             get 
  28.             {  
  29.                 return _NetworkStream;  
  30.             }  
  31.         }  
  32.         #endregion  
  33.         public TcpCacheStream(NetworkStream networkStream)  
  34.         {  
  35.             _NetworkStream = networkStream;  
  36.         }  
  37.         #region Implement stream class  
  38.         public override bool CanRead  
  39.         {  
  40.             get 
  41.             {  
  42.                 return true;  
  43.             }  
  44.         }  
  45.         public override bool CanSeek  
  46.         {  
  47.             get 
  48.             {  
  49.                 return false;  
  50.             }  
  51.         }  
  52.    
  53.         public override bool CanWrite  
  54.         {  
  55.             get 
  56.             {  
  57.                 return true;  
  58.             }  
  59.         }  
  60.          public override void Flush()  
  61.         {  
  62.             NetworkStream.Write(_Buf, 0, _BufLen);  
  63.             NetworkStream.Flush();  
  64.         }  
  65.          public override long Length  
  66.         {  
  67.             get 
  68.             {  
  69.                 throw new Exception("This stream can not seek!");  
  70.             }  
  71.         }  
  72.    
  73.         public override long Position  
  74.         {  
  75.             get 
  76.             {  
  77.                 throw new Exception("This stream can not seek!");  
  78.             }  
  79.    
  80.             set 
  81.             {  
  82.                 throw new Exception("This stream can not seek!");  
  83.             }  
  84.         }  
  85.    
  86.         public override int Read(byte[] buffer, int offset, int count)  
  87.         {  
  88.             int len = 0;  
  89.    
  90.             //If cache is not empty, read from cache  
  91.             if (CacheStream.Length > CacheStream.Position)  
  92.             {  
  93.                 len = CacheStream.Read(buffer, offset, count);  
  94.                 return len;  
  95.             }  
  96.    
  97.             //Fill cache  
  98.             len = NetworkStream.Read(_Buf, 0, BUF_SIZE);  
  99.    
  100.             if (len == 0)  
  101.             {  
  102.                 return 0;  
  103.             }  
  104.    
  105.             CacheStream.Position = 0;  
  106.             CacheStream.Write(_Buf, 0, len);  
  107.             CacheStream.SetLength(len);  
  108.             CacheStream.Position = 0;  
  109.    
  110.             len = CacheStream.Read(buffer, offset, count);  
  111.    
  112.             return len;  
  113.         }  
  114.    
  115.         public override long Seek(long offset, SeekOrigin origin)  
  116.         {  
  117.             throw new Exception("This stream can not seek!");  
  118.         }  
  119.    
  120.         public override void SetLength(long value)  
  121.         {  
  122.             throw new Exception("This stream can not seek!");  
  123.         }  
  124.    
  125.         public override void Write(byte[] buffer, int offset, int count)  
  126.         {  
  127.             if (offset + count > buffer.Length)  
  128.             {  
  129.                 throw new ArgumentException("Count + offset large then buffer.Length");  
  130.             }  
  131.    
  132.             int remain = count - (BUF_SIZE - _BufLen);  
  133.    
  134.             if (remain < 0)  
  135.             {  
  136.                 Array.Copy(buffer, offset, _Buf, _BufLen, count);  
  137.                 _BufLen = BUF_SIZE + remain;  
  138.             }  
  139.             else 
  140.             {  
  141.                 Array.Copy(buffer, offset, _Buf, _BufLen, BUF_SIZE - _BufLen);  
  142.                 NetworkStream.Write(_Buf, 0, _Buf.Length);  
  143.    
  144.                 Array.Copy(buffer, offset + BUF_SIZE - _BufLen, _Buf, 0, remain);  
  145.    
  146.                 _BufLen = remain;  
  147.             }  
  148.         }  
  149.          #endregion  
  150.     } 

原文标题:.Net 下通过缓存提高TCP传输速度

链接:http://www.cnblogs.com/eaglet/archive/2009/11/04/1595887.html

  【责任编辑:彭凡 TEL:(010)68476606】
责任编辑:彭凡 来源: 博客园
相关推荐

2013-03-08 09:57:36

路由器无线传输视频速度

2011-07-04 17:45:45

Qt Sqlite 数据库

2011-02-24 09:42:17

限制传输速度

2010-07-02 09:25:37

.NET 4.0可扩展

2009-11-09 08:53:21

ASP.NET缓存

2009-08-17 16:34:21

.NET分布式缓存Memcached

2020-04-10 08:55:26

TCPIPBBR算法

2016-09-07 15:02:03

ElasticSear索引速度

2011-08-10 15:11:23

SQL Server整理索引碎片重建索引

2009-02-18 09:42:58

TCPISO传输

2010-08-30 08:39:27

无线网络

2024-03-11 15:47:11

RustPython代码

2010-03-23 09:59:52

无线传输速度

2010-10-15 12:39:26

实际无线传输速度

2023-10-17 10:11:50

TCPIP

2010-06-17 17:48:05

TCP传输控制协议

2010-06-09 13:54:13

TCP传输协议

2010-06-09 16:28:50

TCP IP传输协议

2011-05-30 13:28:00

PHP

2011-05-30 13:15:05

PHP
点赞
收藏

51CTO技术栈公众号