天天看点

[转载]C#实现的可复用Socket接收/发送共享缓冲区类

在Socket的接收/发送方法:Send()、BeginSend()、Receive()、BeginReceive()中,第一个参数是字节数数组,表示当前接收数据区或需要发送的数据。普通Socket应用中,往往是接收/发送时创建数组,使用后数组空间由托管堆回收(Socket关闭后其关联的缓冲区情况类似)。显然,频繁创建接收/发送缓冲区将在托管堆上留下很多的内存碎块,影响系统性能。

事实上,在.NET 2.0平台上的Socket传统APM(异步编程模型)中仍然可用该这个技术。下面是修改的BufferManager类:

上述代码中,m_maxSessionCount是Socket服务器最大的可连客户端Socket数,BufferManager构造函数要求该数以及接收和发送缓冲区的大小,从而创建两个大的、可重复使用共享缓冲区。

具体使用步骤如下:

创建一个BufferManager对象 m_bufferManager

获取缓冲区块索引号:m_bufferBlockIndex = m_bufferManager.GetBufferBlockIndex()

异步接收:先计算出缓冲区偏移地址,然后开始接收

异步发送:先考虑发送串长度,然后决定是否使用缓冲区,见随后的代码

不使用块索引号时:m_bufferManager.FreeBufferBlockIndext(m_bufferBlockIndex)回收

下面是申请一个缓冲区索引号的代码示例:

下面是Socket异步接收数据的代码示例:

下面是Socket异步发送字符串datagramText的代码示例:

在数据发送时,如果发送缓冲区大小比实际发送的包长度大,上述异步发送可以使用BufferManager公共缓冲区。否则,需要新建一个发送缓冲区(字节数组)。此外,用共享缓冲区分多次发送长数据包也是一个可考虑的方案,但实现比较复杂(留待以后解决)。数据接收则直接使用BufferManager,因为长数据包由Socket自动分多次接收,不需要考虑分包及包接收顺序等问题。另一个需要注意的是,获取的缓冲区索引块号要记住回收它们。

基于事件驱动的SocketAsyncEventArgs性能的改善,不仅与使用共享缓冲区的技术相关,更与其在完成端口(IOCP)共享SocketAsyncEventArgs对象有关,该对象可重复使用。而在传统的异步Socket处理时,总会创建一个IAsyncResult对象,该对象不可重复使用,且必须调用AsyncWaitHandle.Close()释放资源。显然,共享缓冲区技术只稍稍改善了应用系统的性能,没有从根本上消除Socket的APM的缺陷。

本文转自peterzb博客园博客,原文链接:http://www.cnblogs.com/peterzb/archive/2009/05/29/1491603.html,如需转载请自行联系原作者。