您的位置:首页 > 理论基础 > 计算机网络

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

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

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

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

调用方法很简单

发送过程

objectmsg;


//初始化msg过程省略


System.Net.Sockets.NetworkStream_ClientStream;


//初始化_ClientStream过程省略




//创建TcpCacheStream


TcpCacheStreamtcpStream=newTcpCacheStream(_ClientStream);




//二进制序列化msg对象到TcpCacheStream


IFormatterformatter=newBinaryFormatter();


formatter.Serialize(tcpStream,msg);




//将缓存中最后一包的数据发送出去


tcpStream.Flush();


接收过程



System.Net.Sockets.NetworkStream_ClientStream;


//初始化_ClientStream过程省略




//创建TcpCacheStream


TcpCacheStreamtcpStream=newTcpCacheStream(_ClientStream);




//从TcpCacheStream二进制反序列化


IFormatterformatter=newBinaryFormatter();


objcetresult=formatter.Deserialize(tcpStream);


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

TcpCacheStream的代码如下:

[Serializable]

publicclassTcpCacheStream:Stream

{

#regionPrivatefields

constintBUF_SIZE=4096;

privatebyte[]_Buf=newbyte[BUF_SIZE];


privateMemoryStream_CacheStream=newMemoryStream(BUF_SIZE);

privateNetworkStream_NetworkStream;


privateint_BufLen=0;


#endregion


#regionPrivateproperties


privateMemoryStreamCacheStream

{

get

{

return_CacheStream;

}

}


#endregion



#regionPublicproperties


///<summary>

///getorsettheNetworkStream

///</summary>

publicNetworkStreamNetworkStream

{

get

{

return_NetworkStream;

}

}


#endregion



publicTcpCacheStream(NetworkStreamnetworkStream)

{

_NetworkStream=networkStream;

}


#regionImplementstreamclass


publicoverrideboolCanRead

{

get

{

returntrue;

}

}


publicoverrideboolCanSeek

{

get

{

returnfalse;

}

}


publicoverrideboolCanWrite

{

get

{

returntrue;

}

}


publicoverridevoidFlush()

{

NetworkStream.Write(_Buf,0,_BufLen);

NetworkStream.Flush();

}


publicoverridelongLength

{

get

{

thrownewException("Thisstreamcannotseek!");

}

}


publicoverridelongPosition

{

get

{

thrownewException("Thisstreamcannotseek!");

}


set

{

thrownewException("Thisstreamcannotseek!");

}

}


publicoverrideintRead(byte[]buffer,intoffset,intcount)

{

intlen=0;


//Ifcacheisnotempty,readfromcache

if(CacheStream.Length>CacheStream.Position)

{

len=CacheStream.Read(buffer,offset,count);

returnlen;

}


//Fillcache

len=NetworkStream.Read(_Buf,0,BUF_SIZE);


if(len==0)

{

return0;

}


CacheStream.Position=0;

CacheStream.Write(_Buf,0,len);

CacheStream.SetLength(len);

CacheStream.Position=0;


len=CacheStream.Read(buffer,offset,count);


returnlen;

}


publicoverridelongSeek(longoffset,SeekOriginorigin)

{

thrownewException("Thisstreamcannotseek!");

}


publicoverridevoidSetLength(longvalue)

{

thrownewException("Thisstreamcannotseek!");

}


publicoverridevoidWrite(byte[]buffer,intoffset,intcount)

{

if(offset+count>buffer.Length)

{

thrownewArgumentException("Count+offsetlargethenbuffer.Length");

}


intremain=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

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: