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

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网站上去取,我就不贴出来了
 

服务器端

  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. }

客户端

 
客户端代码也是很简单
  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. }
 

client.cs

  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. }

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

  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. }
这个类我没有测试,但是理论上是没问题的。

C#高性能Socket服务器SocketAsyncEventArgs的实现(IOCP)的更多相关文章

  1. 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP)

    高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...

  2. 转 C#高性能Socket服务器SocketAsyncEventArgs的实现(IOCP)

    原创性申明 本文作者:小竹zz  博客地址:http://blog.csdn.net/zhujunxxxxx/article/details/43573879转载请注明出处引言 我一直在探寻一个高性能 ...

  3. (IOCP)-C#高性能Socket服务器的实现

    C#高性能Socket服务器的实现(IOCP) https://www.jianshu.com/p/c65c0eb59f22 引言 我一直在探寻一个高性能的Socket客户端代码.以前,我使用Sock ...

  4. C#高性能Socket服务器IOCP实现

    引言我一直在探寻一个高性能的Socket客户端代码.以前,我使用Socket类写了一些基于传统异步编程模型的代码(BeginSend.BeginReceive,等等)也看过很多博客的知识,在linux ...

  5. GJM : 【C# 高性能服务器】完成端口、心跳的高性能Socket服务器 [转载]

    感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...

  6. workerman是一个高性能的PHP socket服务器框架

    workerman-chatorkerman是一款纯PHP开发的开源高性能的PHP socket服务器框架.被广泛的用于手机app.手游服务端.网络游戏服务器.聊天室服务器.硬件通讯服务器.智能家居. ...

  7. .Net socket服务器编程之为何也高效

    说到Socket编程,肯定大部分人举手c,c++.可惜现在已没有机会去追随并达到写服务器的水平,所以将就下还是考虑c#版的Socket服务器吧. 经过一番查询,试用.一些数据和事实还是浮出水面,同时对 ...

  8. Netty实现高性能RPC服务器优化篇之消息序列化

    在本人写的前一篇文章中,谈及有关如何利用Netty开发实现,高性能RPC服务器的一些设计思路.设计原理,以及具体的实现方案(具体参见:谈谈如何使用Netty开发实现高性能的RPC服务器).在文章的最后 ...

  9. 高性能Linux服务器 第11章 构建高可用的LVS负载均衡集群

    高性能Linux服务器 第11章 构建高可用的LVS负载均衡集群 libnet软件包<-依赖-heartbeat(包含ldirectord插件(需要perl-MailTools的rpm包)) l ...

随机推荐

  1. 转jmeter 性能测试 JDBC Request (查询数据库获取数据库数据) 的使用

    JDBC Request 这个Sampler可以向数据库发送一个jdbc请求(sql语句),并获取返回的数据库数据进行操作.它经常需要和JDBC Connection Configuration配置原 ...

  2. easyNetq demo

    本demo包含一个类库,2个console程序 1.新建类库  MQHelper,控制台程序  consumer和proc ,控制台程序引用MQHelper 2.使用nuget安装easynwtq 和 ...

  3. 配置Spring的用于解决懒加载问题的过滤器

    <?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" ...

  4. IOS-4-面试题1:黑马程序猿IOS面试题大全

    一.多线程网络 1. 多线程的底层实现? 1> 首先搞清楚什么是线程.什么是多线程 2> Mach是第一个以多线程方式处理任务的系统.因此多线程的底层实现机制是基于Mach的线程 3> ...

  5. C市现在要转移一批罪犯到D市,C市有n名罪犯,按照入狱时间有顺序,另外每个罪犯有一个罪行值,值越大罪越重。现在为了方便管理,市长决定转移入狱时间连续的c名犯人,同时要求转移犯人的罪行值之和不超过t,问有多少种选择的方式?

    // ConsoleApplication12.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" // ConsoleApplication1 ...

  6. Android API Guides---Supporting Tablets and Handsets

    在Android平台上的各种屏幕尺寸的执行和系统调整大小正常应用程序的用户界面.以适应每一个人. 通常情况下,你须要做的是设计你的UI是灵活的,并通过提供替代资源(如又一次定位的一些看法观点或替代尺寸 ...

  7. VSTS跟Kubernetes整合进行CI/CD

    利用VSTS跟Kubernetes整合进行CI/CD   为什么VSTS要搭配Kubernetes? 通常我们在开发管理软件项目的时候都会碰到一个很头痛的问题,就是开发.测试.生产环境不一致,导致开发 ...

  8. redis客户端连接,最大连接数查询与设置

    ##redis客户端连接数 redis通过监听一个TCP端口或socket的方式接收来自客户端的连接, 当与客户端建立连接后,redis内部会进行如下操作:()客户端socket会被设置为非阻塞模式, ...

  9. EasyNVR H5无插件摄像机直播解决方案前端解析之:引用videojs无法自动播放

    关于videojs自动播放问题 播放流媒体多使用videojs来进行播放,videojs,本身自带自动播放属性: 通过添加autoplay(),来完成视频播放的自动加载: player = video ...

  10. process_thread_action

    import psycopg2 import threading conn_fmac = psycopg2.connect(database='filter_useless_mac', user='u ...