原文:C#高性能大容量SOCKET并发(十):SocketAsyncEventArgs线程模型

线程模型

SocketAsyncEventArgs编程模式不支持设置同时工作线程个数,使用的NET的IO线程,由NET底层提供,这点和直接使用完成端口API编程不同。NET底层IO线程也是每个异步事件都是由不同的线程返回到Completed事件,因此在Completed事件需要对用户对象进行加锁,避免同一个用户对象同时触发两个Completed事件。

        void IO_Completed(object sender, SocketAsyncEventArgs asyncEventArgs){AsyncSocketUserToken userToken = asyncEventArgs.UserToken as AsyncSocketUserToken;userToken.ActiveDateTime = DateTime.Now;try{                lock (userToken) //避免同一个userToken同时有多个线程操作{if (asyncEventArgs.LastOperation == SocketAsyncOperation.Receive)ProcessReceive(asyncEventArgs);else if (asyncEventArgs.LastOperation == SocketAsyncOperation.Send)ProcessSend(asyncEventArgs);elsethrow new ArgumentException("The last operation completed on the socket was not a receive or send");}   }catch (Exception E){Program.Logger.ErrorFormat("IO_Completed {0} error, message: {1}", userToken.ConnectSocket, E.Message);Program.Logger.Error(E.StackTrace);}                     }

使用ProceXP可以看到服务端在比较忙的时候,服务的线程会越多。在Completed事件加锁有好处是后续逻辑处理都是串行的,可以不用考虑线程同步。还有一个地方需要注意的是断开超时连接,由于超时连接会调用Shutdown函数来强行中断SOCKET,因此在守护线程调用时,也需要锁住userToken对象。

        public void DaemonThreadStart(){while (m_thread.IsAlive){AsyncSocketUserToken[] userTokenArray = null;m_asyncSocketServer.AsyncSocketUserTokenList.CopyList(ref userTokenArray);for (int i = 0; i < userTokenArray.Length; i++){if (!m_thread.IsAlive)break;try{if ((DateTime.Now - userTokenArray[i].ActiveDateTime).Milliseconds > m_asyncSocketServer.SocketTimeOutMS) //超时Socket断开{lock (userTokenArray[i]){m_asyncSocketServer.CloseClientSocket(userTokenArray[i]);}}}                    catch (Exception E){Program.Logger.ErrorFormat("Daemon thread check timeout socket error, message: {0}", E.Message);Program.Logger.Error(E.StackTrace);}}for (int i = 0; i < 60 * 1000 / 10; i++) //每分钟检测一次{if (!m_thread.IsAlive)break;Thread.Sleep(10);}}}

在CloseClientSocket方法中,对m_asyncSocketUserTokenPool和m_asyncSocketUserTokenList进行处理的时候都有加锁,代码如下:

        public void CloseClientSocket(AsyncSocketUserToken userToken){if (userToken.ConnectSocket == null)return;string socketInfo = string.Format("Local Address: {0} Remote Address: {1}", userToken.ConnectSocket.LocalEndPoint,userToken.ConnectSocket.RemoteEndPoint);Program.Logger.InfoFormat("Client connection disconnected. {0}", socketInfo);try{userToken.ConnectSocket.Shutdown(SocketShutdown.Both);}catch (Exception E) {Program.Logger.ErrorFormat("CloseClientSocket Disconnect client {0} error, message: {1}", socketInfo, E.Message);}userToken.ConnectSocket.Close();userToken.ConnectSocket = null; //释放引用,并清理缓存,包括释放协议对象等资源m_maxNumberAcceptedClients.Release();m_asyncSocketUserTokenPool.Push(userToken);m_asyncSocketUserTokenList.Remove(userToken);}
        public void Push(AsyncSocketUserToken item){if (item == null){throw new ArgumentException("Items added to a AsyncSocketUserToken cannot be null");}lock (m_pool){m_pool.Push(item);}}
        public void Remove(AsyncSocketUserToken userToken){lock (m_list){m_list.Remove(userToken);}}

在有些性能要求更高的系统,特别是在一些C++写的完成端口中,会使用原子操作来代替锁,这样做的好处是不用进行系统内核和用户态切换,性能会高。不过技术比较偏门,不易维护,而且实际表现需要进行多方面测试,这类优化更建议优化业务逻辑,并尽量减少内存分配和释放。

DEMO下载地址:http://download.csdn.net/detail/sqldebug_fan/7467745
免责声明:此代码只是为了演示C#完成端口编程,仅用于学习和研究,切勿用于商业用途。水平有限,C#也属于初学,错误在所难免,欢迎指正和指导。邮箱地址:fansheng_hx@163.com。

C#高性能大容量SOCKET并发(十):SocketAsyncEventArgs线程模型相关推荐

  1. C#高性能大容量SOCKET并发(十一):编写上传客户端

    原文:C#高性能大容量SOCKET并发(十一):编写上传客户端 客户端封装整体框架 客户端编程基于阻塞同步模式,只有数据正常发送或接收才返回,如果发生错误则抛出异常,基于TcpClient进行封装,主 ...

  2. [并发并行]_[线程模型]_[Pthread线程使用模型之一管道Pipeline]

    场景 1.经常在Windows, MacOSX 开发C多线程程序的时候, 经常需要和线程打交道, 如果开发人员的数量不多时, 同时掌握Win32和pthread线程 并不是容易的事情, 而且使用Win ...

  3. 大厂面试官喜欢这样问Redis,双写一致性、并发竞争、线程模型,我整理好了

    你知道的越多,你不知道的越多 点赞再看,养成习惯 https://github.com/java-已经开源,有面试脑图 前言 正文 上几期吊打系列我们提到了Redis的很多知识,还没看的小伙伴可以回顾 ...

  4. 高性能的 socket 通讯服务器(完成端口模型--IOCP)

    2019独角兽企业重金招聘Python工程师标准>>> 很多人费尽心思,都没有找到一个完美的 I/O CP 例程,甚至跟人于误解,先将本人编写的例程公布出来,希望对那些苦苦寻觅的人带 ...

  5. 从根上理解高性能、高并发(一):深入计算机底层,理解线程与线程池

    本文原题"聊聊TCP连接耗时的那些事儿",本次收录已征得作者同意,转载请联系作者.有少许改动. 1.系列文章引言 1.1 文章目的 作为即时通讯技术的开发者来说,高性能.高并发相关 ...

  6. [转]从根上理解高性能、高并发:深入计算机底层,理解线程与线程池

    系列 <从根上理解高性能.高并发(一):深入计算机底层,理解线程与线程池> <从根上理解高性能.高并发(二):深入操作系统,理解I/O与零拷贝技术> <从根上理解高性能. ...

  7. 从根上理解高性能、高并发(七):深入操作系统,一文读懂进程、线程、协程

    本文引用了"一文读懂什么是进程.线程.协程"一文的主要内容,感谢原作者的无私分享. 1.系列文章引言 1.1 文章目的 作为即时通讯技术的开发者来说,高性能.高并发相关的技术概念早 ...

  8. java高并发(十)线程不安全类与写法

    什么是线程不安全类? 如果一个类的对象同时可以被多个线程访问,如果不做特殊的同步与并发处理,就很容易表现出线程不安全的现象,比如抛出异常,比如逻辑处理错误等,这种类就是线程不安全类. StringBu ...

  9. 十四丶并发编程(线程 进程 协程)

    Yuan先生 知识预览 操作系统 回到顶部 操作系统 一 为什么要有操作系统? 现代计算机系统是由一个或者多个处理器,主存,磁盘,打印机,键盘,鼠标显示器,网络接口以及各种其他输入输出设备组成的复杂系 ...

最新文章

  1. 卡巴斯基安全浏览器_卡巴斯基 for windows 全方位安全软件2021注册表清除版
  2. [导入]使用tomcat5.0自带的连接池
  3. 世界首台!我国量子计算机超越早期经典计算机
  4. java创建配置文件_java – 如何创建紧凑的配置文件
  5. 从零写一个编译器(七):语义分析之符号表的数据结构
  6. WinSock I/O 模型 -- WSAEventSelect 模型
  7. 中芯国际:与阿斯麦集团签订购买单 总价12亿美元
  8. escilpse 连接mysql,浅谈docker-compose网络设置之networks
  9. linux第三课:一些注意点
  10. express 模板 及 文件上传
  11. macOS Catalina常见问题汇总
  12. es使用同义词插件注意事项
  13. vr课设《梵高世界》第一人称的解谜游戏
  14. java long型时间戳_深入理解java long 存储时间戳
  15. matlab画图semilogy
  16. 第一个IOS app- 密码管理大师
  17. 什么是抓包?为什么要抓包?
  18. 手机浏览器部分不支持8位rgba色值
  19. [游戏技术]VampireSurvivors PC版修改
  20. 调制、数字调制、模拟调制比较

热门文章

  1. 百货中心供应链管理系统
  2. pandas -表的横向合并 纵向合并
  3. 使用【飞桨】实现【手写数字识别】
  4. 微分方程 ode45() 求解并绘制曲线
  5. 使用matlab做可重复性实验结果——rng
  6. excel函数SUMPRODUCT
  7. python UnicodeEncodeError: 'gbk' codec can't encode character ...
  8. DB2命令行查看执行计划
  9. Centos7 编译安装 Nginx、MariaDB、PHP
  10. 时间复杂度和空间复杂度3 - 数据结构和算法05