关闭

.Net 下通过缓存提高TCP传输速度

644人阅读 评论(0) 收藏 举报

 .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 前先进行缓存。

    调用方法很简单

   

  • 发送过程
object msg;
//初始化 msg 过程省略
System.Net.Sockets.NetworkStream _ClientStream;
//初始化 _ClientStream 过程省略
 
//创建TcpCacheStream 
TcpCacheStream tcpStream = new TcpCacheStream(_ClientStream);
 
//二进制序列化 msg 对象到 TcpCacheStream 
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(tcpStream, msg);
 
//将缓存中最后一包的数据发送出去
tcpStream.Flush();

  

  • 接收过程
 
System.Net.Sockets.NetworkStream _ClientStream;
//初始化 _ClientStream 过程省略
 
//创建TcpCacheStream 
TcpCacheStream tcpStream = new TcpCacheStream(_ClientStream);
 
//从 TcpCacheStream 二进制反序列化
IFormatter formatter = new BinaryFormatter();
objcet result = formatter.Deserialize(tcpStream);

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

 

TcpCacheStream 的代码如下:

    [Serializable]
    public class TcpCacheStream : Stream
    {
        #region Private fields
        const int BUF_SIZE = 4096;
        private byte[] _Buf = new byte[BUF_SIZE];
 
        private MemoryStream _CacheStream = new MemoryStream(BUF_SIZE);
        private NetworkStream _NetworkStream;
 
        private int _BufLen = 0;
 
        #endregion
 
        #region Private properties
 
        private MemoryStream CacheStream
        {
            get
            {
                return _CacheStream;
            }
        }
 
        #endregion
 
 
        #region Public properties
 
        /// <summary>
        /// get or set the Network Stream
        /// </summary>
        public NetworkStream NetworkStream
        {
            get
            {
                return _NetworkStream;
            }
        }
 
        #endregion
 
 
        public TcpCacheStream(NetworkStream networkStream)
        {
            _NetworkStream = networkStream;
        }
 
        #region Implement stream class
 
        public override bool CanRead
        {
            get
            {
                return true;
            }
        }
 
        public override bool CanSeek
        {
            get
            {
                return false;
            }
        }
 
        public override bool CanWrite
        {
            get
            {
                return true;
            }
        }
 
        public override void Flush()
        {
            NetworkStream.Write(_Buf, 0, _BufLen);
            NetworkStream.Flush();
        }
 
        public override long Length
        {
            get
            {
                throw new Exception("This stream can not seek!");
            }
        }
 
        public override long Position
        {
            get
            {
                throw new Exception("This stream can not seek!");
            }
 
            set
            {
                throw new Exception("This stream can not seek!");
            }
        }
 
        public override int Read(byte[] buffer, int offset, int count)
        {
            int len = 0;
 
            //If cache is not empty, read from cache
            if (CacheStream.Length > CacheStream.Position)
            {
                len = CacheStream.Read(buffer, offset, count);
                return len;
            }
 
            //Fill cache
            len = NetworkStream.Read(_Buf, 0, BUF_SIZE);
 
            if (len == 0)
            {
                return 0;
            }
 
            CacheStream.Position = 0;
            CacheStream.Write(_Buf, 0, len);
            CacheStream.SetLength(len);
            CacheStream.Position = 0;
 
            len = CacheStream.Read(buffer, offset, count);
 
            return len;
        }
 
        public override long Seek(long offset, SeekOrigin origin)
        {
            throw new Exception("This stream can not seek!");
        }
 
        public override void SetLength(long value)
        {
            throw new Exception("This stream can not seek!");
        }
 
        public override void Write(byte[] buffer, int offset, int count)
        {
            if (offset + count > buffer.Length)
            {
                throw new ArgumentException("Count + offset large then buffer.Length");
            }
 
            int remain = count - (BUF_SIZE - _BufLen);
 
            if (remain < 0)
            {
                Array.Copy(buffer, offset, _Buf, _BufLen, count);
                _BufLen = BUF_SIZE + remain;
            }
            else
            {
                Array.Copy(buffer, offset, _Buf, _BufLen, BUF_SIZE - _BufLen);
                NetworkStream.Write(_Buf, 0, _Buf.Length);
 
                Array.Copy(buffer, offset + BUF_SIZE - _BufLen, _Buf, 0, remain);
 
                _BufLen = remain;
            }
        }
 
        #endregion
    }
0
0
查看评论

.Net 下通过缓存提高TCP传输速度

.Net 提供了一个NetworkStream 用于TCP 的读写,实际使用时发现直接操作效率很低,哪怕把TCP 的发送缓存和接受缓存设置很大也没有太大提高。后来在对 NetworkStream 读写前设置了缓存,性能一下子提高了很多。    从实际测试结果看设置自己的...
  • canduecho
  • canduecho
  • 2009-12-06 21:38
  • 234

.Net 下通过缓存提高TCP传输速度

Net 提供了一个NetworkStream 用于TCP 的读写,实际使用时发现直接操作效率很低,哪怕把TCP 的发送缓存和接受缓存设置很大也没有太大提高。后来在对 NetworkStream 读写前设置了缓存,性能一下子提高了很多。    从实际测试结果看设置自己的写...
  • susubuhui
  • susubuhui
  • 2010-01-06 17:24
  • 430

C# .Net 下通过缓存提高TCP传输速度

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

提高TCP并发连接数和连接速度的方法

1)在内存或高速缓存cache中构建查找表,所述查找表存储根据已有TCP连接的源IP地址、目的IP地址、源端口地址、目的端口地址计算得到的签名值,并实现TCB与查找表中的相应签名值形成关联; 2)当进行TCP连接的创建、删除时,先根据TCP连接的源IP地址、目的IP地址、源端口地址、目的端口地址计算...
  • jinxinliu1
  • jinxinliu1
  • 2014-03-14 14:51
  • 1623

TCP传输小数据包效率问题(转载)

本文转自 http://blog.csdn.net/stamhe/archive/2009/09/19/4569530.aspx      s摘要:当使用TCP传输小型数据包时,程序的设计是相当重要的。如果在设计方案中不对TCP数据包的延迟应答,N...
  • zhu_bao_xiang
  • zhu_bao_xiang
  • 2015-10-13 09:28
  • 1080

骗你不是人 硬盘传输速度提升4倍的方法

2010年04月01日 07:22 IT168网站原创 作者:IT168内存硬盘频道 编辑:林伟明 在普通的日子,我们是不会刻意强调内容的真伪,毕竟IT168平时的评测报告是建立在事实的基础上。但今天的情况有点特殊,因为是“愚人节”。为保证下面的内容是真实,我们可以大胆说出承诺——骗你不是人。 ...
  • cnbird2008
  • cnbird2008
  • 2012-03-06 11:51
  • 9858

TCP与UDP模拟实验学习笔记

程序和相关解释可以参考:http://nile.wpi.edu/NS/ ,为英文文档。 本文假设已有课本教材和相关代码。 这个实验的仿真网络结构图包含:两个传输节点/路由器和数据接收端。传输节点到路由器的传递延迟是10ms,路由器到接收端是20ms。链路的管理机制是DropTail...
  • zy416548283
  • zy416548283
  • 2012-11-29 12:25
  • 2297

TCP传输速度的计算

<br /> 传输速度=通告窗口*每一个数据包的大小/往返 延时<br /> <br />比如:<br />通告窗口=15<br />数据包大小=1040Byte<br />往返延时=30ms<br ...
  • piyajee
  • piyajee
  • 2010-09-09 22:43
  • 1644

[FMS]FMS之P2P直播介绍

一、方案简介 目 前视频直播通用的方案有两种,分别是单播模式和多播模式。单播模式虽然有着数据流稳定的特点,但具有地域化问题,且随着客户量的增加,服务器负载也随之增 大,需要投入大量的硬件设备以及巨额的带宽费用。多播模式通常体现为现今的P2P技术。P2P模式解决了单播模式的问题,在提高传输速度和...
  • pilot10
  • pilot10
  • 2016-02-17 17:29
  • 1188

如何提高缓存命中率

缓存命中率的介绍命中:可以直接通过缓存获取到需要的数据。不命中:无法直接通过缓存获取到想要的数据,需要再次查询数据库或者执行其它的操作。原因可能是由于缓存中根本不存在,或者缓存已经过期。通常来讲,缓存的命中率越高则表示使用缓存的收益越高,应用的性能越好(响应时间越短、吞吐量越高),抗并发的能力越强。...
  • dinglang_2009
  • dinglang_2009
  • 2016-12-01 12:59
  • 6027
    个人资料
    • 访问:12002038次
    • 积分:66781
    • 等级:
    • 排名:第38名
    • 原创:675篇
    • 转载:2295篇
    • 译文:0篇
    • 评论:558条
    文章分类
    文章存档
    最新评论
    计算流量