zoukankan      html  css  js  c++  java
  • C#高性能Socket服务器SocketAsyncEventArgs的实现(IOCP)

    原创性申明

    本文作者:小竹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的方法模式。这种新模式并不要求为每个套接字操作分配操作上下文对象。

    代码下载:http://download.csdn.net/detail/zhujunxxxxx/8431289 这里的代码优化了的

    目标

    在上面微软提供的例子我觉得不是很完整,没有具体一个流程,只是受到客户端消息后发送相同内容给客户端,初学者不容易看懂流程,因为我花了一天的时间来实现一个功能齐全的IOCP服务器,

    效果如下

    代码

    首先是ICOPServer.cs 这个类是IOCP服务器的核心类,目前这个类是网络上比较全的代码,MSDN上面的例子都没有我的全

    [csharp] view plain copy print?

    1. using System; 
    2. using System.Collections.Generic; 
    3. using System.Linq; 
    4. using System.Text; 
    5. using System.Net.Sockets; 
    6. using System.Net; 
    7. using System.Threading; 
    8. namespace ServerTest 
    9. /// <summary>
    10. /// IOCP SOCKET服务器
    11. /// </summary>
    12. public class IOCPServer : IDisposable 
    13.     { 
    14. const int opsToPreAlloc = 2; 
    15.         #region Fields
    16. /// <summary>
    17. /// 服务器程序允许的最大客户端连接数
    18. /// </summary>
    19. private int _maxClient; 
    20. /// <summary>
    21. /// 监听Socket,用于接受客户端的连接请求
    22. /// </summary>
    23. private Socket _serverSock; 
    24. /// <summary>
    25. /// 当前的连接的客户端数
    26. /// </summary>
    27. private int _clientCount; 
    28. /// <summary>
    29. /// 用于每个I/O Socket操作的缓冲区大小
    30. /// </summary>
    31. private int _bufferSize = 1024; 
    32. /// <summary>
    33. /// 信号量
    34. /// </summary>
    35.         Semaphore _maxAcceptedClients; 
    36. /// <summary>
    37. /// 缓冲区管理
    38. /// </summary>
    39.         BufferManager _bufferManager; 
    40. /// <summary>
    41. /// 对象池
    42. /// </summary>
    43.         SocketAsyncEventArgsPool _objectPool; 
    44. private bool disposed = false; 
    45.         #endregion
    46.         #region Properties
    47. /// <summary>
    48. /// 服务器是否正在运行
    49. /// </summary>
    50. public bool IsRunning { get; private set; } 
    51. /// <summary>
    52. /// 监听的IP地址
    53. /// </summary>
    54. public IPAddress Address { get; private set; } 
    55. /// <summary>
    56. /// 监听的端口
    57. /// </summary>
    58. public int Port { get; private set; } 
    59. /// <summary>
    60. /// 通信使用的编码
    61. /// </summary>
    62. public Encoding Encoding { get; set; } 
    63.         #endregion
    64.         #region Ctors
    65. /// <summary>
    66. /// 异步IOCP SOCKET服务器
    67. /// </summary>
    68. /// <param name="listenPort">监听的端口</param>
    69. /// <param name="maxClient">最大的客户端数量</param>
    70. public IOCPServer(int listenPort,int maxClient) 
    71.             : this(IPAddress.Any, listenPort, maxClient) 
    72.         { 
    73.         } 
    74. /// <summary>
    75. /// 异步Socket TCP服务器
    76. /// </summary>
    77. /// <param name="localEP">监听的终结点</param>
    78. /// <param name="maxClient">最大客户端数量</param>
    79. public IOCPServer(IPEndPoint localEP, int maxClient) 
    80.             : this(localEP.Address, localEP.Port,maxClient) 
    81.         { 
    82.         } 
    83. /// <summary>
    84. /// 异步Socket TCP服务器
    85. /// </summary>
    86. /// <param name="localIPAddress">监听的IP地址</param>
    87. /// <param name="listenPort">监听的端口</param>
    88. /// <param name="maxClient">最大客户端数量</param>
    89. public IOCPServer(IPAddress localIPAddress, int listenPort, int maxClient) 
    90.         { 
    91. this.Address = localIPAddress; 
    92. this.Port = listenPort; 
    93. this.Encoding = Encoding.Default; 
    94.             _maxClient = maxClient; 
    95.             _serverSock = new Socket(localIPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 
    96.             _bufferManager = new BufferManager(_bufferSize * _maxClient * opsToPreAlloc,_bufferSize); 
    97.             _objectPool = new SocketAsyncEventArgsPool(_maxClient); 
    98.             _maxAcceptedClients = new Semaphore(_maxClient, _maxClient);  
    99.         } 
    100.         #endregion
    101.         #region 初始化
    102. /// <summary>
    103. /// 初始化函数
    104. /// </summary>
    105. public void Init() 
    106.         { 
    107. // Allocates one large byte buffer which all I/O operations use a piece of.  This gaurds
    108. // against memory fragmentation
    109.             _bufferManager.InitBuffer(); 
    110. // preallocate pool of SocketAsyncEventArgs objects
    111.             SocketAsyncEventArgs readWriteEventArg; 
    112. for (int i = 0; i < _maxClient; i++) 
    113.             { 
    114. //Pre-allocate a set of reusable SocketAsyncEventArgs
    115.                 readWriteEventArg = new SocketAsyncEventArgs(); 
    116.                 readWriteEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(OnIOCompleted); 
    117.                 readWriteEventArg.UserToken = null; 
    118. // assign a byte buffer from the buffer pool to the SocketAsyncEventArg object
    119.                 _bufferManager.SetBuffer(readWriteEventArg); 
    120. // add SocketAsyncEventArg to the pool
    121.                 _objectPool.Push(readWriteEventArg); 
    122.             } 
    123.         } 
    124.         #endregion
    125.         #region Start
    126. /// <summary>
    127. /// 启动
    128. /// </summary>
    129. public void Start() 
    130.         { 
    131. if (!IsRunning) 
    132.             { 
    133.                 Init(); 
    134.                 IsRunning = true; 
    135.                 IPEndPoint localEndPoint = new IPEndPoint(Address, Port); 
    136. // 创建监听socket
    137.                 _serverSock = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 
    138. //_serverSock.ReceiveBufferSize = _bufferSize;
    139. //_serverSock.SendBufferSize = _bufferSize;
    140. if (localEndPoint.AddressFamily == AddressFamily.InterNetworkV6) 
    141.                 { 
    142. // 配置监听socket为 dual-mode (IPv4 & IPv6)
    143. // 27 is equivalent to IPV6_V6ONLY socket option in the winsock snippet below,
    144.                     _serverSock.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false); 
    145.                     _serverSock.Bind(new IPEndPoint(IPAddress.IPv6Any, localEndPoint.Port)); 
    146.                 } 
    147. else
    148.                 { 
    149.                     _serverSock.Bind(localEndPoint); 
    150.                 } 
    151. // 开始监听
    152.                 _serverSock.Listen(this._maxClient); 
    153. // 在监听Socket上投递一个接受请求。
    154.                 StartAccept(null); 
    155.             } 
    156.         } 
    157.         #endregion
    158.         #region Stop
    159. /// <summary>
    160. /// 停止服务
    161. /// </summary>
    162. public void Stop() 
    163.         { 
    164. if (IsRunning) 
    165.             { 
    166.                 IsRunning = false; 
    167.                 _serverSock.Close(); 
    168. //TODO 关闭对所有客户端的连接
    169.             } 
    170.         } 
    171.         #endregion
    172.         #region Accept
    173. /// <summary>
    174. /// 从客户端开始接受一个连接操作
    175. /// </summary>
    176. private void StartAccept(SocketAsyncEventArgs asyniar) 
    177.         { 
    178. if (asyniar == null) 
    179.             { 
    180.                 asyniar = new SocketAsyncEventArgs(); 
    181.                 asyniar.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted); 
    182.             } 
    183. else
    184.             { 
    185. //socket must be cleared since the context object is being reused
    186.                 asyniar.AcceptSocket = null; 
    187.             } 
    188.             _maxAcceptedClients.WaitOne(); 
    189. if (!_serverSock.AcceptAsync(asyniar)) 
    190.             { 
    191.                 ProcessAccept(asyniar); 
    192. //如果I/O挂起等待异步则触发AcceptAsyn_Asyn_Completed事件
    193. //此时I/O操作同步完成,不会触发Asyn_Completed事件,所以指定BeginAccept()方法
    194.             } 
    195.         } 
    196. /// <summary>
    197. /// accept 操作完成时回调函数
    198. /// </summary>
    199. /// <param name="sender">Object who raised the event.</param>
    200. /// <param name="e">SocketAsyncEventArg associated with the completed accept operation.</param>
    201. private void OnAcceptCompleted(object sender, SocketAsyncEventArgs e) 
    202.         { 
    203.             ProcessAccept(e); 
    204.         } 
    205. /// <summary>
    206. /// 监听Socket接受处理
    207. /// </summary>
    208. /// <param name="e">SocketAsyncEventArg associated with the completed accept operation.</param>
    209. private void ProcessAccept(SocketAsyncEventArgs e) 
    210.         { 
    211. if (e.SocketError == SocketError.Success) 
    212.             { 
    213.                 Socket s = e.AcceptSocket;//和客户端关联的socket
    214. if (s.Connected) 
    215.                 { 
    216. try
    217.                     { 
    218.                         Interlocked.Increment(ref _clientCount);//原子操作加1
    219.                         SocketAsyncEventArgs asyniar = _objectPool.Pop(); 
    220.                         asyniar.UserToken = s; 
    221.                         Log4Debug(String.Format("客户 {0} 连入, 共有 {1} 个连接。", s.RemoteEndPoint.ToString(), _clientCount)); 
    222. if (!s.ReceiveAsync(asyniar))//投递接收请求
    223.                         { 
    224.                             ProcessReceive(asyniar); 
    225.                         } 
    226.                     } 
    227. catch (SocketException ex) 
    228.                     { 
    229.                         Log4Debug(String.Format("接收客户 {0} 数据出错, 异常信息: {1} 。", s.RemoteEndPoint, ex.ToString())); 
    230. //TODO 异常处理
    231.                     } 
    232. //投递下一个接受请求
    233.                     StartAccept(e); 
    234.                 } 
    235.             } 
    236.         } 
    237.         #endregion
    238.         #region 发送数据
    239. /// <summary>
    240. /// 异步的发送数据
    241. /// </summary>
    242. /// <param name="e"></param>
    243. /// <param name="data"></param>
    244. public void Send(SocketAsyncEventArgs e, byte[] data) 
    245.         { 
    246. if (e.SocketError == SocketError.Success) 
    247.             { 
    248.                 Socket s = e.AcceptSocket;//和客户端关联的socket
    249. if (s.Connected) 
    250.                 { 
    251.                     Array.Copy(data, 0, e.Buffer, 0, data.Length);//设置发送数据
    252. //e.SetBuffer(data, 0, data.Length); //设置发送数据
    253. if (!s.SendAsync(e))//投递发送请求,这个函数有可能同步发送出去,这时返回false,并且不会引发SocketAsyncEventArgs.Completed事件
    254.                     { 
    255. // 同步发送时处理发送完成事件
    256.                         ProcessSend(e); 
    257.                     } 
    258. else
    259.                     { 
    260.                         CloseClientSocket(e); 
    261.                     } 
    262.                 } 
    263.             } 
    264.         } 
    265. /// <summary>
    266. /// 同步的使用socket发送数据
    267. /// </summary>
    268. /// <param name="socket"></param>
    269. /// <param name="buffer"></param>
    270. /// <param name="offset"></param>
    271. /// <param name="size"></param>
    272. /// <param name="timeout"></param>
    273. public void Send(Socket socket, byte[] buffer, int offset, int size, int timeout) 
    274.         { 
    275.             socket.SendTimeout = 0; 
    276. int startTickCount = Environment.TickCount; 
    277. int sent = 0; // how many bytes is already sent
    278. do
    279.             { 
    280. if (Environment.TickCount > startTickCount + timeout) 
    281.                 { 
    282. //throw new Exception("Timeout.");
    283.                 } 
    284. try
    285.                 { 
    286.                     sent += socket.Send(buffer, offset + sent, size - sent, SocketFlags.None); 
    287.                 } 
    288. catch (SocketException ex) 
    289.                 { 
    290. if (ex.SocketErrorCode == SocketError.WouldBlock || 
    291.                     ex.SocketErrorCode == SocketError.IOPending || 
    292.                     ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable) 
    293.                     { 
    294. // socket buffer is probably full, wait and try again
    295.                         Thread.Sleep(30); 
    296.                     } 
    297. else
    298.                     { 
    299. throw ex; // any serious error occurr
    300.                     } 
    301.                 } 
    302.             } while (sent < size); 
    303.         } 
    304. /// <summary>
    305. /// 发送完成时处理函数
    306. /// </summary>
    307. /// <param name="e">与发送完成操作相关联的SocketAsyncEventArg对象</param>
    308. private void ProcessSend(SocketAsyncEventArgs e) 
    309.         { 
    310. if (e.SocketError == SocketError.Success) 
    311.             { 
    312.                 Socket s = (Socket)e.UserToken; 
    313. //TODO
    314.             } 
    315. else
    316.             { 
    317.                 CloseClientSocket(e); 
    318.             } 
    319.         } 
    320.         #endregion
    321.         #region 接收数据
    322. /// <summary>
    323. ///接收完成时处理函数
    324. /// </summary>
    325. /// <param name="e">与接收完成操作相关联的SocketAsyncEventArg对象</param>
    326. private void ProcessReceive(SocketAsyncEventArgs e) 
    327.         { 
    328. if (e.SocketError == SocketError.Success)//if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
    329.             { 
    330. // 检查远程主机是否关闭连接
    331. if (e.BytesTransferred > 0) 
    332.                 { 
    333.                     Socket s = (Socket)e.UserToken; 
    334. //判断所有需接收的数据是否已经完成
    335. if (s.Available == 0) 
    336.                     { 
    337. //从侦听者获取接收到的消息。
    338. //String received = Encoding.ASCII.GetString(e.Buffer, e.Offset, e.BytesTransferred);
    339. //echo the data received back to the client
    340. //e.SetBuffer(e.Offset, e.BytesTransferred);
    341. byte[] data = new byte[e.BytesTransferred]; 
    342.                         Array.Copy(e.Buffer, e.Offset, data, 0, data.Length);//从e.Buffer块中复制数据出来,保证它可重用
    343. string info=Encoding.Default.GetString(data); 
    344.                         Log4Debug(String.Format("收到 {0} 数据为 {1}",s.RemoteEndPoint.ToString(),info)); 
    345. //TODO 处理数据
    346. //增加服务器接收的总字节数。
    347.                     } 
    348. if (!s.ReceiveAsync(e))//为接收下一段数据,投递接收请求,这个函数有可能同步完成,这时返回false,并且不会引发SocketAsyncEventArgs.Completed事件
    349.                     { 
    350. //同步接收时处理接收完成事件
    351.                         ProcessReceive(e); 
    352.                     } 
    353.                 } 
    354.             } 
    355. else
    356.             { 
    357.                 CloseClientSocket(e); 
    358.             } 
    359.         } 
    360.         #endregion
    361.         #region 回调函数
    362. /// <summary>
    363. /// 当Socket上的发送或接收请求被完成时,调用此函数
    364. /// </summary>
    365. /// <param name="sender">激发事件的对象</param>
    366. /// <param name="e">与发送或接收完成操作相关联的SocketAsyncEventArg对象</param>
    367. private void OnIOCompleted(object sender, SocketAsyncEventArgs e) 
    368.         { 
    369. // Determine which type of operation just completed and call the associated handler.
    370. switch (e.LastOperation) 
    371.             { 
    372. case SocketAsyncOperation.Accept: 
    373.                     ProcessAccept(e); 
    374. break; 
    375. case SocketAsyncOperation.Receive: 
    376.                     ProcessReceive(e); 
    377. break; 
    378. default: 
    379. throw new ArgumentException("The last operation completed on the socket was not a receive or send"); 
    380.             } 
    381.         } 
    382.         #endregion
    383.         #region Close
    384. /// <summary>
    385. /// 关闭socket连接
    386. /// </summary>
    387. /// <param name="e">SocketAsyncEventArg associated with the completed send/receive operation.</param>
    388. private void CloseClientSocket(SocketAsyncEventArgs e) 
    389.         { 
    390.             Log4Debug(String.Format("客户 {0} 断开连接!",((Socket)e.UserToken).RemoteEndPoint.ToString())); 
    391.             Socket s = e.UserToken as Socket; 
    392.             CloseClientSocket(s, e); 
    393.         } 
    394. /// <summary>
    395. /// 关闭socket连接
    396. /// </summary>
    397. /// <param name="s"></param>
    398. /// <param name="e"></param>
    399. private void CloseClientSocket(Socket s, SocketAsyncEventArgs e) 
    400.         { 
    401. try
    402.             { 
    403.                 s.Shutdown(SocketShutdown.Send); 
    404.             } 
    405. catch (Exception) 
    406.             { 
    407. // Throw if client has closed, so it is not necessary to catch.
    408.             } 
    409. finally
    410.             { 
    411.                 s.Close(); 
    412.             } 
    413.             Interlocked.Decrement(ref _clientCount); 
    414.             _maxAcceptedClients.Release(); 
    415.             _objectPool.Push(e);//SocketAsyncEventArg 对象被释放,压入可重用队列。
    416.         } 
    417.         #endregion
    418.         #region Dispose
    419. /// <summary>
    420. /// Performs application-defined tasks associated with freeing,
    421. /// releasing, or resetting unmanaged resources.
    422. /// </summary>
    423. public void Dispose() 
    424.         { 
    425.             Dispose(true); 
    426.             GC.SuppressFinalize(this); 
    427.         } 
    428. /// <summary>
    429. /// Releases unmanaged and - optionally - managed resources
    430. /// </summary>
    431. /// <param name="disposing"><c>true</c> to release
    432. /// both managed and unmanaged resources; <c>false</c>
    433. /// to release only unmanaged resources.</param>
    434. protected virtual void Dispose(bool disposing) 
    435.         { 
    436. if (!this.disposed) 
    437.             { 
    438. if (disposing) 
    439.                 { 
    440. try
    441.                     { 
    442.                         Stop(); 
    443. if (_serverSock != null) 
    444.                         { 
    445.                             _serverSock = null; 
    446.                         } 
    447.                     } 
    448. catch (SocketException ex) 
    449.                     { 
    450. //TODO 事件
    451.                     } 
    452.                 } 
    453.                 disposed = true; 
    454.             } 
    455.         } 
    456.         #endregion
    457. public void Log4Debug(string msg) 
    458.         { 
    459.             Console.WriteLine("notice:"+msg); 
    460.         } 
    461.     } 
    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;
    
                for (int i = 0; i < _maxClient; i++)
                {
                    //Pre-allocate a set of reusable SocketAsyncEventArgs
                    readWriteEventArg = new SocketAsyncEventArgs();
                    readWriteEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(OnIOCompleted);
                    readWriteEventArg.UserToken = null;
    
                    // assign a byte buffer from the buffer pool to the SocketAsyncEventArg object
                    _bufferManager.SetBuffer(readWriteEventArg);
    
                    // add SocketAsyncEventArg to the pool
                    _objectPool.Push(readWriteEventArg);
                }
    
            }
    
            #endregion
    
            #region Start
            /// <summary>
            /// 启动
            /// </summary>
            public void Start()
            {
                if (!IsRunning)
                {
                    Init();
                    IsRunning = true;
                    IPEndPoint localEndPoint = new IPEndPoint(Address, Port);
                    // 创建监听socket
                    _serverSock = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                    //_serverSock.ReceiveBufferSize = _bufferSize;
                    //_serverSock.SendBufferSize = _bufferSize;
                    if (localEndPoint.AddressFamily == AddressFamily.InterNetworkV6)
                    {
                        // 配置监听socket为 dual-mode (IPv4 & IPv6) 
                        // 27 is equivalent to IPV6_V6ONLY socket option in the winsock snippet below,
                        _serverSock.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false);
                        _serverSock.Bind(new IPEndPoint(IPAddress.IPv6Any, localEndPoint.Port));
                    }
                    else
                    {
                        _serverSock.Bind(localEndPoint);
                    }
                    // 开始监听
                    _serverSock.Listen(this._maxClient);
                    // 在监听Socket上投递一个接受请求。
                    StartAccept(null);
                }
            }
            #endregion
    
            #region Stop
    
            /// <summary>
            /// 停止服务
            /// </summary>
            public void Stop()
            {
                if (IsRunning)
                {
                    IsRunning = false;
                    _serverSock.Close();
                    //TODO 关闭对所有客户端的连接
    
                }
            }
    
            #endregion
    
    
            #region Accept
    
            /// <summary>
            /// 从客户端开始接受一个连接操作
            /// </summary>
            private void StartAccept(SocketAsyncEventArgs asyniar)
            {
                if (asyniar == null)
                {
                    asyniar = new SocketAsyncEventArgs();
                    asyniar.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);
                }
                else
                {
                    //socket must be cleared since the context object is being reused
                    asyniar.AcceptSocket = null;
                }
                _maxAcceptedClients.WaitOne();
                if (!_serverSock.AcceptAsync(asyniar))
                {
                    ProcessAccept(asyniar);
                    //如果I/O挂起等待异步则触发AcceptAsyn_Asyn_Completed事件
                    //此时I/O操作同步完成,不会触发Asyn_Completed事件,所以指定BeginAccept()方法
                }
            }
    
            /// <summary>
            /// accept 操作完成时回调函数
            /// </summary>
            /// <param name="sender">Object who raised the event.</param>
            /// <param name="e">SocketAsyncEventArg associated with the completed accept operation.</param>
            private void OnAcceptCompleted(object sender, SocketAsyncEventArgs e)
            {
                ProcessAccept(e);
            }
    
            /// <summary>
            /// 监听Socket接受处理
            /// </summary>
            /// <param name="e">SocketAsyncEventArg associated with the completed accept operation.</param>
            private void ProcessAccept(SocketAsyncEventArgs e)
            {
                if (e.SocketError == SocketError.Success)
                {
                    Socket s = e.AcceptSocket;//和客户端关联的socket
                    if (s.Connected)
                    {
                        try
                        {
                            
                            Interlocked.Increment(ref _clientCount);//原子操作加1
                            SocketAsyncEventArgs asyniar = _objectPool.Pop();
                            asyniar.UserToken = s;
    
                            Log4Debug(String.Format("客户 {0} 连入, 共有 {1} 个连接。", s.RemoteEndPoint.ToString(), _clientCount));
                            
                            if (!s.ReceiveAsync(asyniar))//投递接收请求
                            {
                                ProcessReceive(asyniar);
                            }
                        }
                        catch (SocketException ex)
                        {
                            Log4Debug(String.Format("接收客户 {0} 数据出错, 异常信息: {1} 。", s.RemoteEndPoint, ex.ToString()));
                            //TODO 异常处理
                        }
                        //投递下一个接受请求
                        StartAccept(e);
                    }
                }
            }
    
            #endregion
    
            #region 发送数据
    
            /// <summary>
            /// 异步的发送数据
            /// </summary>
            /// <param name="e"></param>
            /// <param name="data"></param>
            public void Send(SocketAsyncEventArgs e, byte[] data)
            {
                if (e.SocketError == SocketError.Success)
                {
                    Socket s = e.AcceptSocket;//和客户端关联的socket
                    if (s.Connected)
                    {
                        Array.Copy(data, 0, e.Buffer, 0, data.Length);//设置发送数据
    
                        //e.SetBuffer(data, 0, data.Length); //设置发送数据
                        if (!s.SendAsync(e))//投递发送请求,这个函数有可能同步发送出去,这时返回false,并且不会引发SocketAsyncEventArgs.Completed事件
                        {
                            // 同步发送时处理发送完成事件
                            ProcessSend(e);
                        }
                        else
                        {
                            CloseClientSocket(e);
                        }
                    }
                }
            }
    
            /// <summary>
            /// 同步的使用socket发送数据
            /// </summary>
            /// <param name="socket"></param>
            /// <param name="buffer"></param>
            /// <param name="offset"></param>
            /// <param name="size"></param>
            /// <param name="timeout"></param>
            public void Send(Socket socket, byte[] buffer, int offset, int size, int timeout)
            {
                socket.SendTimeout = 0;
                int startTickCount = Environment.TickCount;
                int sent = 0; // how many bytes is already sent
                do
                {
                    if (Environment.TickCount > startTickCount + timeout)
                    {
                        //throw new Exception("Timeout.");
                    }
                    try
                    {
                        sent += socket.Send(buffer, offset + sent, size - sent, SocketFlags.None);
                    }
                    catch (SocketException ex)
                    {
                        if (ex.SocketErrorCode == SocketError.WouldBlock ||
                        ex.SocketErrorCode == SocketError.IOPending ||
                        ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
                        {
                            // socket buffer is probably full, wait and try again
                            Thread.Sleep(30);
                        }
                        else
                        {
                            throw ex; // any serious error occurr
                        }
                    }
                } while (sent < size);
            }
    
    
            /// <summary>
            /// 发送完成时处理函数
            /// </summary>
            /// <param name="e">与发送完成操作相关联的SocketAsyncEventArg对象</param>
            private void ProcessSend(SocketAsyncEventArgs e)
            {
                if (e.SocketError == SocketError.Success)
                {
                    Socket s = (Socket)e.UserToken;
    
                    //TODO
                }
                else
                {
                    CloseClientSocket(e);
                }
            }
    
            #endregion
    
            #region 接收数据
    
    
            /// <summary>
            ///接收完成时处理函数
            /// </summary>
            /// <param name="e">与接收完成操作相关联的SocketAsyncEventArg对象</param>
            private void ProcessReceive(SocketAsyncEventArgs e)
            {
                if (e.SocketError == SocketError.Success)//if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
                {
                    // 检查远程主机是否关闭连接
                    if (e.BytesTransferred > 0)
                    {
                        Socket s = (Socket)e.UserToken;
                        //判断所有需接收的数据是否已经完成
                        if (s.Available == 0)
                        {
                            //从侦听者获取接收到的消息。 
                            //String received = Encoding.ASCII.GetString(e.Buffer, e.Offset, e.BytesTransferred);
                            //echo the data received back to the client
                            //e.SetBuffer(e.Offset, e.BytesTransferred);
    
                            byte[] data = new byte[e.BytesTransferred];
                            Array.Copy(e.Buffer, e.Offset, data, 0, data.Length);//从e.Buffer块中复制数据出来,保证它可重用
    
                            string info=Encoding.Default.GetString(data);
                            Log4Debug(String.Format("收到 {0} 数据为 {1}",s.RemoteEndPoint.ToString(),info));
                            //TODO 处理数据
    
                            //增加服务器接收的总字节数。
                        }
    
                        if (!s.ReceiveAsync(e))//为接收下一段数据,投递接收请求,这个函数有可能同步完成,这时返回false,并且不会引发SocketAsyncEventArgs.Completed事件
                        {
                            //同步接收时处理接收完成事件
                            ProcessReceive(e);
                        }
                    }
                }
                else
                {
                    CloseClientSocket(e);
                }
            }
    
            #endregion
    
            #region 回调函数
    
            /// <summary>
            /// 当Socket上的发送或接收请求被完成时,调用此函数
            /// </summary>
            /// <param name="sender">激发事件的对象</param>
            /// <param name="e">与发送或接收完成操作相关联的SocketAsyncEventArg对象</param>
            private void OnIOCompleted(object sender, SocketAsyncEventArgs e)
            {
                // Determine which type of operation just completed and call the associated handler.
                switch (e.LastOperation)
                {
                    case SocketAsyncOperation.Accept:
                        ProcessAccept(e);
                        break;
                    case SocketAsyncOperation.Receive:
                        ProcessReceive(e);
                        break;
                    default:
                        throw new ArgumentException("The last operation completed on the socket was not a receive or send");
                }
            }
    
            #endregion
    
            #region Close
            /// <summary>
            /// 关闭socket连接
            /// </summary>
            /// <param name="e">SocketAsyncEventArg associated with the completed send/receive operation.</param>
            private void CloseClientSocket(SocketAsyncEventArgs e)
            {
                Log4Debug(String.Format("客户 {0} 断开连接!",((Socket)e.UserToken).RemoteEndPoint.ToString()));
                Socket s = e.UserToken as Socket;
                CloseClientSocket(s, e);
            }
    
            /// <summary>
            /// 关闭socket连接
            /// </summary>
            /// <param name="s"></param>
            /// <param name="e"></param>
            private void CloseClientSocket(Socket s, SocketAsyncEventArgs e)
            {
                try
                {
                    s.Shutdown(SocketShutdown.Send);
                }
                catch (Exception)
                {
                    // Throw if client has closed, so it is not necessary to catch.
                }
                finally
                {
                    s.Close();
                }
                Interlocked.Decrement(ref _clientCount);
                _maxAcceptedClients.Release();
                _objectPool.Push(e);//SocketAsyncEventArg 对象被释放,压入可重用队列。
            }
            #endregion
    
            #region Dispose
            /// <summary>
            /// Performs application-defined tasks associated with freeing, 
            /// releasing, or resetting unmanaged resources.
            /// </summary>
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
    
            /// <summary>
            /// Releases unmanaged and - optionally - managed resources
            /// </summary>
            /// <param name="disposing"><c>true</c> to release 
            /// both managed and unmanaged resources; <c>false</c> 
            /// to release only unmanaged resources.</param>
            protected virtual void Dispose(bool disposing)
            {
                if (!this.disposed)
                {
                    if (disposing)
                    {
                        try
                        {
                            Stop();
                            if (_serverSock != null)
                            {
                                _serverSock = null;
                            }
                        }
                        catch (SocketException ex)
                        {
                            //TODO 事件
                        }
                    }
                    disposed = true;
                }
            }
            #endregion
    
            public void Log4Debug(string msg)
            {
                Console.WriteLine("notice:"+msg);
            }
    
        }
    }
    


    BufferManager.cs 这个类是缓存管理类,是采用MSDN上面的例子一样的 地址: https://msdn.microsoft.com/zh-cn/library/bb517542.aspx

    SocketAsyncEventArgsPool.cs 这个类也是来自MSDN的 地址:https://msdn.microsoft.com/zh-cn/library/system.net.sockets.socketasynceventargs.aspx

    需要的话自己到MSDN网站上去取,我就不贴出来了

    服务器端

    [csharp] view plain copy print?

    1. static void Main(string[] args) 
    2.         { 
    3.             IOCPServer server = new IOCPServer(8088, 1024); 
    4.             server.Start(); 
    5.             Console.WriteLine("服务器已启动...."); 
    6.             System.Console.ReadLine(); 
    7.         } 
    static void Main(string[] args)
            {
    
                IOCPServer server = new IOCPServer(8088, 1024);
                server.Start();
                Console.WriteLine("服务器已启动....");
                System.Console.ReadLine();
            }

    客户端

    客户端代码也是很简单

    [csharp] view plain copy print?

    1. static void Main(string[] args) 
    2.         { 
    3.             IPAddress remote=IPAddress.Parse("192.168.3.4"); 
    4.             client c = new client(8088,remote); 
    5.             c.connect(); 
    6.             Console.WriteLine("服务器连接成功!"); 
    7. while (true) 
    8.             { 
    9.                 Console.Write("send>"); 
    10. string msg=Console.ReadLine(); 
    11. if (msg == "exit") 
    12. break; 
    13.                 c.send(msg); 
    14.             } 
    15.             c.disconnect(); 
    16.             Console.ReadLine(); 
    17.         } 
    static void Main(string[] args)
            {
                IPAddress remote=IPAddress.Parse("192.168.3.4");
                client c = new client(8088,remote);
    
                c.connect();
                Console.WriteLine("服务器连接成功!");
                while (true)
                {
                    Console.Write("send>");
                    string msg=Console.ReadLine();
                    if (msg == "exit")
                        break;
                    c.send(msg);
                }
                c.disconnect();
                Console.ReadLine();
            }

    client.cs

    [csharp] view plain copy print?

    1. public class client 
    2.     { 
    3. public TcpClient _client; 
    4. public int port; 
    5. public IPAddress remote; 
    6. public client(int port,IPAddress remote) 
    7.         { 
    8. this.port = port; 
    9. this.remote = remote; 
    10.         } 
    11. public void connect() 
    12.         { 
    13. this._client=new TcpClient(); 
    14.             _client.Connect(remote, port); 
    15.         } 
    16. public void disconnect() 
    17.         { 
    18.             _client.Close(); 
    19.         } 
    20. public void send(string msg) 
    21.         { 
    22. byte[] data=Encoding.Default.GetBytes(msg); 
    23.             _client.GetStream().Write(data, 0, data.Length); 
    24.         } 
    25.     } 
    public class client
        {
    
            public TcpClient _client;
    
            public int port;
    
            public IPAddress remote;
    
            public client(int port,IPAddress remote)
            {
    
                this.port = port;
                this.remote = remote;
            }
    
            public void connect()
            {
                this._client=new TcpClient();
                _client.Connect(remote, port);
            }
            public void disconnect()
            {
                _client.Close();
            }
            public void send(string msg)
            {
                byte[] data=Encoding.Default.GetBytes(msg);
                _client.GetStream().Write(data, 0, data.Length);
            }
        }


    IOCPClient类,使用SocketAsyncEventArgs类建立一个Socket客户端。虽然MSDN说这个类特别设计给网络服务器应用,但也没有限制在客户端代码中使用APM。下面给出了IOCPClient类的样例代码:

    [csharp] view plain copy print?

    1. public class IOCPClient 
    2.    { 
    3. /// <summary>
    4. /// 连接服务器的socket
    5. /// </summary>
    6. private Socket _clientSock; 
    7. /// <summary>
    8. /// 用于服务器执行的互斥同步对象
    9. /// </summary>
    10. private static Mutex mutex = new Mutex(); 
    11. /// <summary>
    12. /// Socket连接标志
    13. /// </summary>
    14. private Boolean _connected = false; 
    15. private const int ReceiveOperation = 1, SendOperation = 0; 
    16. private static AutoResetEvent[] 
    17.                 autoSendReceiveEvents = new AutoResetEvent[] 
    18.         { 
    19. new AutoResetEvent(false), 
    20. new AutoResetEvent(false) 
    21.         }; 
    22. /// <summary>
    23. /// 服务器监听端点
    24. /// </summary>
    25. private IPEndPoint _remoteEndPoint; 
    26. public IOCPClient(IPEndPoint local,IPEndPoint remote) 
    27.        { 
    28.            _clientSock = new Socket(local.AddressFamily,SocketType.Stream, ProtocolType.Tcp); 
    29.            _remoteEndPoint = remote; 
    30.        } 
    31.        #region 连接服务器
    32. /// <summary>
    33. /// 连接远程服务器
    34. /// </summary>
    35. public void Connect() 
    36.        { 
    37.            SocketAsyncEventArgs connectArgs = new SocketAsyncEventArgs(); 
    38.            connectArgs.UserToken = _clientSock; 
    39.            connectArgs.RemoteEndPoint = _remoteEndPoint; 
    40.            connectArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnConnected); 
    41.            mutex.WaitOne(); 
    42. if (!_clientSock.ConnectAsync(connectArgs))//异步连接
    43.            { 
    44.                ProcessConnected(connectArgs); 
    45.            } 
    46.        } 
    47. /// <summary>
    48. /// 连接上的事件
    49. /// </summary>
    50. /// <param name="sender"></param>
    51. /// <param name="e"></param>
    52. void OnConnected(object sender, SocketAsyncEventArgs e) 
    53.        { 
    54.            mutex.ReleaseMutex(); 
    55. //设置Socket已连接标志。
    56.            _connected = (e.SocketError == SocketError.Success); 
    57.        } 
    58. /// <summary>
    59. /// 处理连接服务器
    60. /// </summary>
    61. /// <param name="e"></param>
    62. private void ProcessConnected(SocketAsyncEventArgs e) 
    63.        { 
    64. //TODO
    65.        } 
    66.        #endregion
    67.        #region 发送消息
    68. /// <summary>
    69. /// 向服务器发送消息
    70. /// </summary>
    71. /// <param name="data"></param>
    72. public void Send(byte[] data) 
    73.        { 
    74.            SocketAsyncEventArgs asyniar = new SocketAsyncEventArgs(); 
    75.            asyniar.Completed += new EventHandler<SocketAsyncEventArgs>(OnSendComplete); 
    76.            asyniar.SetBuffer(data, 0, data.Length); 
    77.            asyniar.UserToken = _clientSock; 
    78.            asyniar.RemoteEndPoint = _remoteEndPoint; 
    79.            autoSendReceiveEvents[SendOperation].WaitOne(); 
    80. if (!_clientSock.SendAsync(asyniar))//投递发送请求,这个函数有可能同步发送出去,这时返回false,并且不会引发SocketAsyncEventArgs.Completed事件
    81.            { 
    82. // 同步发送时处理发送完成事件
    83.                ProcessSend(asyniar); 
    84.            } 
    85.        } 
    86. /// <summary>
    87. /// 发送操作的回调方法
    88. /// </summary>
    89. /// <param name="sender"></param>
    90. /// <param name="e"></param>
    91. private void OnSendComplete(object sender, SocketAsyncEventArgs e) 
    92.        { 
    93. //发出发送完成信号。
    94.            autoSendReceiveEvents[SendOperation].Set(); 
    95.            ProcessSend(e); 
    96.        } 
    97. /// <summary>
    98. /// 发送完成时处理函数
    99. /// </summary>
    100. /// <param name="e">与发送完成操作相关联的SocketAsyncEventArg对象</param>
    101. private void ProcessSend(SocketAsyncEventArgs e) 
    102.        { 
    103. //TODO
    104.        } 
    105.        #endregion
    106.        #region 接收消息
    107. /// <summary>
    108. /// 开始监听服务端数据
    109. /// </summary>
    110. /// <param name="e"></param>
    111. public void StartRecive(SocketAsyncEventArgs e) 
    112.        { 
    113. //准备接收。
    114.            Socket s = e.UserToken as Socket; 
    115. byte[] receiveBuffer = new byte[255]; 
    116.            e.SetBuffer(receiveBuffer, 0, receiveBuffer.Length); 
    117.            e.Completed += new EventHandler<SocketAsyncEventArgs>(OnReceiveComplete); 
    118.            autoSendReceiveEvents[ReceiveOperation].WaitOne(); 
    119. if (!s.ReceiveAsync(e)) 
    120.            { 
    121.                ProcessReceive(e); 
    122.            } 
    123.        } 
    124. /// <summary>
    125. /// 接收操作的回调方法
    126. /// </summary>
    127. /// <param name="sender"></param>
    128. /// <param name="e"></param>
    129. private void OnReceiveComplete(object sender, SocketAsyncEventArgs e) 
    130.        { 
    131. //发出接收完成信号。
    132.            autoSendReceiveEvents[ReceiveOperation].Set(); 
    133.            ProcessReceive(e); 
    134.        } 
    135. /// <summary>
    136. ///接收完成时处理函数
    137. /// </summary>
    138. /// <param name="e">与接收完成操作相关联的SocketAsyncEventArg对象</param>
    139. private void ProcessReceive(SocketAsyncEventArgs e) 
    140.        { 
    141. if (e.SocketError == SocketError.Success) 
    142.            { 
    143. // 检查远程主机是否关闭连接
    144. if (e.BytesTransferred > 0) 
    145.                { 
    146.                    Socket s = (Socket)e.UserToken; 
    147. //判断所有需接收的数据是否已经完成
    148. if (s.Available == 0) 
    149.                    { 
    150. byte[] data = new byte[e.BytesTransferred]; 
    151.                        Array.Copy(e.Buffer, e.Offset, data, 0, data.Length);//从e.Buffer块中复制数据出来,保证它可重用
    152. //TODO 处理数据
    153.                    } 
    154. if (!s.ReceiveAsync(e))//为接收下一段数据,投递接收请求,这个函数有可能同步完成,这时返回false,并且不会引发SocketAsyncEventArgs.Completed事件
    155.                    { 
    156. //同步接收时处理接收完成事件
    157.                        ProcessReceive(e); 
    158.                    } 
    159.                } 
    160.            } 
    161.        } 
    162.        #endregion
    163. public void Close() 
    164.        { 
    165.            _clientSock.Disconnect(false); 
    166.        } 
    167. /// <summary>
    168. /// 失败时关闭Socket,根据SocketError抛出异常。
    169. /// </summary>
    170. /// <param name="e"></param>
    171. private void ProcessError(SocketAsyncEventArgs e) 
    172.        { 
    173.            Socket s = e.UserToken as Socket; 
    174. if (s.Connected) 
    175.            { 
    176. //关闭与客户端关联的Socket
    177. try
    178.                { 
    179.                    s.Shutdown(SocketShutdown.Both); 
    180.                } 
    181. catch (Exception) 
    182.                { 
    183. //如果客户端处理已经关闭,抛出异常
    184.                } 
    185. finally
    186.                { 
    187. if (s.Connected) 
    188.                    { 
    189.                        s.Close(); 
    190.                    } 
    191.                } 
    192.            } 
    193. //抛出SocketException
    194. throw new SocketException((Int32)e.SocketError); 
    195.        } 
    196. /// <summary>
    197. /// 释放SocketClient实例
    198. /// </summary>
    199. public void Dispose() 
    200.        { 
    201.            mutex.Close(); 
    202.            autoSendReceiveEvents[SendOperation].Close(); 
    203.            autoSendReceiveEvents[ReceiveOperation].Close(); 
    204. if (_clientSock.Connected) 
    205.            { 
    206.                _clientSock.Close(); 
    207.            } 
    208.        } 
    209.    } 
     public class IOCPClient
        {
            /// <summary>
            /// 连接服务器的socket
            /// </summary>
            private Socket _clientSock;
    
            /// <summary>
            /// 用于服务器执行的互斥同步对象
            /// </summary>
            private static Mutex mutex = new Mutex();
            /// <summary>
            /// Socket连接标志
            /// </summary>
            private Boolean _connected = false;
    
            private const int ReceiveOperation = 1, SendOperation = 0;
    
            private static AutoResetEvent[]
                     autoSendReceiveEvents = new AutoResetEvent[]
             {
                 new AutoResetEvent(false),
                 new AutoResetEvent(false)
             };
    
            /// <summary>
            /// 服务器监听端点
            /// </summary>
            private IPEndPoint _remoteEndPoint;
    
            public IOCPClient(IPEndPoint local,IPEndPoint remote)
            {
                _clientSock = new Socket(local.AddressFamily,SocketType.Stream, ProtocolType.Tcp);
                _remoteEndPoint = remote;
            }
    
            #region 连接服务器
    
            /// <summary>
            /// 连接远程服务器
            /// </summary>
            public void Connect()
            {
                SocketAsyncEventArgs connectArgs = new SocketAsyncEventArgs();
    
                connectArgs.UserToken = _clientSock;
                connectArgs.RemoteEndPoint = _remoteEndPoint;
                connectArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnConnected);
                mutex.WaitOne();
                if (!_clientSock.ConnectAsync(connectArgs))//异步连接
                {
                    ProcessConnected(connectArgs);
                }
                
            }
            /// <summary>
            /// 连接上的事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            void OnConnected(object sender, SocketAsyncEventArgs e)
            {
                mutex.ReleaseMutex();
                //设置Socket已连接标志。 
                _connected = (e.SocketError == SocketError.Success);
            }
            /// <summary>
            /// 处理连接服务器
            /// </summary>
            /// <param name="e"></param>
            private void ProcessConnected(SocketAsyncEventArgs e)
            {
                //TODO
            }
    
            #endregion
    
            #region 发送消息
            /// <summary>
            /// 向服务器发送消息
            /// </summary>
            /// <param name="data"></param>
            public void Send(byte[] data)
            {
                SocketAsyncEventArgs asyniar = new SocketAsyncEventArgs();
                asyniar.Completed += new EventHandler<SocketAsyncEventArgs>(OnSendComplete);
                asyniar.SetBuffer(data, 0, data.Length);
                asyniar.UserToken = _clientSock;
                asyniar.RemoteEndPoint = _remoteEndPoint;
                autoSendReceiveEvents[SendOperation].WaitOne();
                if (!_clientSock.SendAsync(asyniar))//投递发送请求,这个函数有可能同步发送出去,这时返回false,并且不会引发SocketAsyncEventArgs.Completed事件
                {
                    // 同步发送时处理发送完成事件
                    ProcessSend(asyniar);
                }
            }
    
            /// <summary>
            /// 发送操作的回调方法
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void OnSendComplete(object sender, SocketAsyncEventArgs e)
            {
                //发出发送完成信号。 
                autoSendReceiveEvents[SendOperation].Set();
                ProcessSend(e);
            }
    
            /// <summary>
            /// 发送完成时处理函数
            /// </summary>
            /// <param name="e">与发送完成操作相关联的SocketAsyncEventArg对象</param>
            private void ProcessSend(SocketAsyncEventArgs e)
            {
                //TODO
            }
            #endregion
    
            #region 接收消息
            /// <summary>
            /// 开始监听服务端数据
            /// </summary>
            /// <param name="e"></param>
            public void StartRecive(SocketAsyncEventArgs e)
            {
                //准备接收。 
                Socket s = e.UserToken as Socket;
                byte[] receiveBuffer = new byte[255];
                e.SetBuffer(receiveBuffer, 0, receiveBuffer.Length);
                e.Completed += new EventHandler<SocketAsyncEventArgs>(OnReceiveComplete);
                autoSendReceiveEvents[ReceiveOperation].WaitOne();
                if (!s.ReceiveAsync(e))
                {
                    ProcessReceive(e);
                }
            }
    
            /// <summary>
            /// 接收操作的回调方法
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void OnReceiveComplete(object sender, SocketAsyncEventArgs e)
            {
                //发出接收完成信号。 
                autoSendReceiveEvents[ReceiveOperation].Set();
                ProcessReceive(e);
            }
    
            /// <summary>
            ///接收完成时处理函数
            /// </summary>
            /// <param name="e">与接收完成操作相关联的SocketAsyncEventArg对象</param>
            private void ProcessReceive(SocketAsyncEventArgs e)
            {
                if (e.SocketError == SocketError.Success)
                {
                    // 检查远程主机是否关闭连接
                    if (e.BytesTransferred > 0)
                    {
                        Socket s = (Socket)e.UserToken;
                        //判断所有需接收的数据是否已经完成
                        if (s.Available == 0)
                        {
                            byte[] data = new byte[e.BytesTransferred];
                            Array.Copy(e.Buffer, e.Offset, data, 0, data.Length);//从e.Buffer块中复制数据出来,保证它可重用
    
                            //TODO 处理数据
                        }
    
                        if (!s.ReceiveAsync(e))//为接收下一段数据,投递接收请求,这个函数有可能同步完成,这时返回false,并且不会引发SocketAsyncEventArgs.Completed事件
                        {
                            //同步接收时处理接收完成事件
                            ProcessReceive(e);
                        }
                    }
                }
            }
    
            #endregion
    
    
            public void Close()
            {
                _clientSock.Disconnect(false);
            }
    
            /// <summary>
            /// 失败时关闭Socket,根据SocketError抛出异常。
            /// </summary>
            /// <param name="e"></param>
     
            private void ProcessError(SocketAsyncEventArgs e)
            {
                Socket s = e.UserToken as Socket;
                if (s.Connected)
                {
                    //关闭与客户端关联的Socket
                    try
                    {
                        s.Shutdown(SocketShutdown.Both);
                    }
                    catch (Exception)
                    {
                        //如果客户端处理已经关闭,抛出异常 
                    }
                    finally
                    {
                        if (s.Connected)
                        {
                            s.Close();
                        }
                    }
                }
                //抛出SocketException 
                throw new SocketException((Int32)e.SocketError);
            }
    
    
            /// <summary>
            /// 释放SocketClient实例
            /// </summary>
            public void Dispose()
            {
                mutex.Close();
                autoSendReceiveEvents[SendOperation].Close();
                autoSendReceiveEvents[ReceiveOperation].Close();
                if (_clientSock.Connected)
                {
                    _clientSock.Close();
                }
            }
    
        }

    这个类我没有测试,但是理论上是没问题的。

    本文地址:http://blog.csdn.net/zhujunxxxxx/article/details/43573879

  • 相关阅读:
    从数据到代码—通过代码生成机制实现强类型编程
    .NET中oledb访问access含子查询的语句的参数置换顺序
    Android开发入门学习
    Shell脚本初步学习鸟哥Linux私房菜基础学习篇
    rpm打包学习
    关于计算机工作方向的几点想法
    source insight中文注释乱码问题的解决方案
    makefilerpm编译软件,输出依赖软件包的编译顺序
    在android中资源文件夹中添加一个新的图片资源
    Linux批量替换某种类型文件中的字符串sed和grep命令使用
  • 原文地址:https://www.cnblogs.com/HappinessZhao/p/7745974.html
Copyright © 2011-2022 走看看