原创性申明
本文作者:小竹zz 博客地址:http://blog.csdn.net/zhujunxxxxx/article/details/43573879转载请注明出处
引言
我一直在探寻一个高性能的Socket客户端代码。以前,我使用Socket类写了一些基于传统异步编程模型的代码(BeginSend、BeginReceive,等等)也看过很多博客的知识,在linux中有poll和epoll来实现,在windows下面
微软MSDN中也提供了SocketAsyncEventArgs这个类来实现IOCP 地址: https://msdn.microsoft.com/zh-cn/library/system.net.sockets.socketasynceventargs.aspx
NET Framework中的APM也称为Begin/End模式。这是因为会调用Begin方法来启动异步操作,然后返回一个IAsyncResult 对象。可以选择将一个代理作为参数提供给Begin方法,异步操作完成时会调用该方法。或者,一个线程可以等待 IAsyncResult.AsyncWaitHandle。当回调被调用或发出等待信号时,就会调用End方法来获取异步操作的结果。这种模式很灵活,使用相对简单,在 .NET Framework 中非常常见。
但是,您必须注意,如果进行大量异步套接字操作,是要付出代价的。针对每次操作,都必须创建一个IAsyncResult对象,而且该对象不能被重复使用。由于大量使用对象分配和垃圾收集,这会影响性能。为了解决这个问题,新版本提供了另一个使用套接字上执行异步I/O的方法模式。这种新模式并不要求为每个套接字操作分配操作上下文对象。
微软MSDN中也提供了SocketAsyncEventArgs这个类来实现IOCP 地址: https://msdn.microsoft.com/zh-cn/library/system.net.sockets.socketasynceventargs.aspx
NET Framework中的APM也称为Begin/End模式。这是因为会调用Begin方法来启动异步操作,然后返回一个IAsyncResult 对象。可以选择将一个代理作为参数提供给Begin方法,异步操作完成时会调用该方法。或者,一个线程可以等待 IAsyncResult.AsyncWaitHandle。当回调被调用或发出等待信号时,就会调用End方法来获取异步操作的结果。这种模式很灵活,使用相对简单,在 .NET Framework 中非常常见。
但是,您必须注意,如果进行大量异步套接字操作,是要付出代价的。针对每次操作,都必须创建一个IAsyncResult对象,而且该对象不能被重复使用。由于大量使用对象分配和垃圾收集,这会影响性能。为了解决这个问题,新版本提供了另一个使用套接字上执行异步I/O的方法模式。这种新模式并不要求为每个套接字操作分配操作上下文对象。
代码下载:
http://download.csdn.net/detail/zhujunxxxxx/8431289 这里的代码优化了的
目标
在上面微软提供的例子我觉得不是很完整,没有具体一个流程,只是受到客户端消息后发送相同内容给客户端,初学者不容易看懂流程,因为我花了一天的时间来实现一个功能齐全的IOCP服务器,
效果如下
代码
首先是ICOPServer.cs 这个类是IOCP服务器的核心类,目前这个类是网络上比较全的代码,MSDN上面的例子都没有我的全
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace ServerTest
{
/// <summary>
/// IOCP SOCKET服务器
/// </summary>
public class IOCPServer : IDisposable
{
const int opsToPreAlloc = 2;
#region Fields
/// <summary>
/// 服务器程序允许的最大客户端连接数
/// </summary>
private int _maxClient;
/// <summary>
/// 监听Socket,用于接受客户端的连接请求
/// </summary>
private Socket _serverSock;
/// <summary>
/// 当前的连接的客户端数
/// </summary>
private int _clientCount;
/// <summary>
/// 用于每个I/O Socket操作的缓冲区大小
/// </summary>
private int _bufferSize = 1024;
/// <summary>
/// 信号量
/// </summary>
Semaphore _maxAcceptedClients;
/// <summary>
/// 缓冲区管理
/// </summary>
BufferManager _bufferManager;
/// <summary>
/// 对象池
/// </summary>
SocketAsyncEventArgsPool _objectPool;
private bool disposed = false;
#endregion
#region Properties
/// <summary>
/// 服务器是否正在运行
/// </summary>
public bool IsRunning { get; private set; }
/// <summary>
/// 监听的IP地址
/// </summary>
public IPAddress Address { get; private set; }
/// <summary>
/// 监听的端口
/// </summary>
public int Port { get; private set; }
/// <summary>
/// 通信使用的编码
/// </summary>
public Encoding Encoding { get; set; }
#endregion
#region Ctors
/// <summary>
/// 异步IOCP SOCKET服务器
/// </summary>
/// <param name="listenPort">监听的端口</param>
/// <param name="maxClient">最大的客户端数量</param>
public IOCPServer(int listenPort,int maxClient)
: this(IPAddress.Any, listenPort, maxClient)
{
}
/// <summary>
/// 异步Socket TCP服务器
/// </summary>
/// <param name="localEP">监听的终结点</param>
/// <param name="maxClient">最大客户端数量</param>
public IOCPServer(IPEndPoint localEP, int maxClient)
: this(localEP.Address, localEP.Port,maxClient)
{
}
/// <summary>
/// 异步Socket TCP服务器
/// </summary>
/// <param name="localIPAddress">监听的IP地址</param>
/// <param name="listenPort">监听的端口</param>
/// <param name="maxClient">最大客户端数量</param>
public IOCPServer(IPAddress localIPAddress, int listenPort, int maxClient)
{
this.Address = localIPAddress;
this.Port = listenPort;
this.Encoding = Encoding.Default;
_maxClient = maxClient;
_serverSock = new Socket(localIPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_bufferManager = new BufferManager(_bufferSize * _maxClient * opsToPreAlloc,_bufferSize);
_objectPool = new SocketAsyncEventArgsPool(_maxClient);
_maxAcceptedClients = new Semaphore(_maxClient, _maxClient);
}
#endregion
#region 初始化
/// <summary>
/// 初始化函数
/// </summary>
public void Init()
{
// Allocates one large byte buffer which all I/O operations use a piece of. This gaurds
// against memory fragmentation
_bufferManager.InitBuffer();
// preallocate pool of SocketAsyncEventArgs objects
SocketAsyncEventArgs readWriteEventArg;