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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM