使用ConcurrentQueue并发集合来设计网络服务器端
来源:互联网 发布:mac 不能玩炉石传说么 编辑:程序博客网 时间:2024/05/29 10:20
HP-SOCKET 很好的网络底层引擎,让我可以直接做服务器的其它部分。
HP-SOCKET 把客户端的请求放到了事件响应中,客户端接入服务器会通知到相应的函数:
OnAccept 客户端连接服务器触发
OnSend 服务器送数据给客户端触发
OnReceive 服务器收到客户端数据触发
OnClose 客户端关闭服务器触发
OnError 网络错误触发
网络服务器端,只需从这些触发的函数中收集数据,然后发回客户端即可。
客户端是多个对应于一个服务器的。
在OnReceive中,可能同时有很多的客户端都在给服务器发数据。
服务器我使用记录集来存放客户端对象,其他业务数据对象可使用记录集来存放。因为C#的对象查询LINQ功能对记录集的操作太完美了。
对于记录集List的操作,服务器设计专门的单线程来保证数据更新的一致性。
这种场景是,多个客户端请求和一个单一的对记录集的操作。
使用ConcurrentQueue并发集合刚好可以应付这种清空。
ConcurrentQueue并发集合来构成一个【队列】,它支持多个生产者产生数据放【队列】中,一个消费者从【队列】中一次一次的拿走数据。按照先进先出。
这里,我把多个客户端的请求放到【队列】中,启动一个单一线程,从【队列】中取一个请求,去更新记录集,并接下来处理业务逻辑更新记录集。
这样可以始终做到更新记录集的数据一致性,因为就只有一个线程在更新他们。
//100ms 一次操作 private void c1() { while (true) { Thread.Sleep(100); try { //操作1 从操作队列中取最上面的来更新【服务器对象集合】 ObjOpertion n = null; if (opertions.TryDequeue(out n)) { opertionTotal--; label8.Text = opertionTotal.ToString(); if (n.Kind == 100) { clients.Add(new ClientInfo { ConnId = n.ConnId, IpAddress = n.IpAddress, Port = n.Port, USER = "", Rtxt = "", Stxt = "", logontime = DateTime.Now.ToString() }); addMsg(string.Format(" > [{0},OnAccept] ", n.ConnId)); } else if (n.Kind == 200) { var a = (from ClientInfo in clients where ClientInfo.ConnId == n.ConnId select ClientInfo).FirstOrDefault(); //这个ID收了多少次计数 a.Receives++; // 从pData中获取数据,叠加放rtxt字符串中 a.Rtxt += n.Rtxt; } else if (n.Kind == 300) { var a = (from ClientInfo in clients where ClientInfo.ConnId == n.ConnId select ClientInfo).FirstOrDefault(); a.Sends++; } else if (n.Kind == 400) { // 客户离开了,删除这个client对象 var a = (from ClientInfo in clients where ClientInfo.ConnId == n.ConnId select ClientInfo).FirstOrDefault(); clients.Remove(a); addMsg(string.Format(" > [{0},OnClose]", n.ConnId)); } } //操作2 基于业务逻辑来更新【服务器对象集合】 foreach (ClientInfo a in clients) { //查找有没有"." if ( (!String.IsNullOrWhiteSpace(a.Rtxt)) && ( a.Rtxt.IndexOf('.') > -1) ) { //取"."前的字符串,并按"|"分割 string thistime_str = a.Rtxt.Substring(0, a.Rtxt.IndexOf('.')); string[] s = thistime_str.Split('|'); //////////////////////////// //1|user|pass //////////////////////////// if ((sint(s[0]) == 1) && (a.USER.Length == 0)) //空用户,才能认证 { //查询密码表 var sn = (from USERPASS in users where USERPASS.USER == s[1] && USERPASS.PASS == s[2] select USERPASS).FirstOrDefault(); var other = (from ClientInfo in clients where ClientInfo.USER == s[1] select ClientInfo).FirstOrDefault(); if ((sn != null) && (other == null)) //有用户密码记录,并不允许多次连接 { a.USER = sn.USER; addMsg(string.Format(" > [{0},login success]", a.ConnId ) ); sendToClient(a.ConnId, "101|you are welcome."); } else { sendToClient(a.ConnId, "101|login authentication failure."); server.Disconnect(a.ConnId); addMsg(string.Format(" > [{0}, login authentication failure]", a.ConnId)); } } //////////////////////////////////////////////// //如果是2|, 就是消息文本数据 2|othername|txt //////////////////////////////////////////////// else if ((sint(s[0]) == 2) && (a.USER.Length>0) ) { var other = (from ClientInfo in clients where ClientInfo.USER == s[1] select ClientInfo).FirstOrDefault(); if (other != null) { sendToClient(other.ConnId, "102|" + a.USER + "|" + s[2] + "."); //转发送其它客户端 102|name|txt } else { sendToClient(a.ConnId, "102|" + s[1] + "|不在线,数据无法转发."); //告诉本客户端,数据无法转发 } } //////////////////////////////////////////////// //如果是9|, 就是心跳数据 发回客户端 109|客户端对象个数. //////////////////////////////////////////////// else if ((sint(s[0]) == 9) && (a.USER.Length > 0)) { sendToClient(a.ConnId, "109|" + clients.Count.ToString() + "."); } //////////////////////////////////////////////// //即使是无效的指令,也执行一次后,清除该指令 //////////////////////////////////////////////// a.Rtxt = a.Rtxt.Substring(a.Rtxt.IndexOf('.') + 1); } } //操作3 服务器对象操作,list 的删除操作比较特别 // if (delid.ToInt64() > 0) // { // delid = new IntPtr(0); // } } catch (Exception ex) { addMsg(ex.Message); } } }
源代码下载
http://download.csdn.net/detail/ot512csdn/9361567
0 0
- 使用ConcurrentQueue并发集合来设计网络服务器端
- 【C#】55. .Net中的并发集合——ConcurrentQueue
- C# 并发队列ConcurrentQueue
- 高并发服务器端设计
- 网络并发服务器设计
- 买票系统模拟Java高并发(ConcurrentQueue的解决方案)
- 使用任务集合来限制高并发导致服务器超负载的解决方案
- 使用gitosis来配置管理git服务器端
- Unix网络编程(七)使用select来实现服务器的并发
- 数据库表设计中使用横向表切割来降低并发冲突
- c# ConcurrentQueue
- 网络编程中设计并发服务器,使用多进程与多线程有什么区别?
- 服务器端设计
- 使用Pushlet来实现服务器端向客户端推送信息
- 使用Pushlet来实现服务器端向客户端推送信息
- Nodejs 使用eventproxy来控制并发
- 并发集合
- 并发集合
- Linux:主机linux内核版本升级实验
- HDU2014--青年歌手大奖赛_评委会打分
- poj1149 PIGS
- Winsocket编程
- MySQL单列索引和组合索引的区别介绍
- 使用ConcurrentQueue并发集合来设计网络服务器端
- 弘扬的博客,一些基础的和进阶的安卓教程
- RealSense SDK 开发笔记 (三)获取R200的图像(OpenCV Mat)
- Scla富包装器
- Unable to locate appropriate constructor on class [hibernatePojo.ShareResource]
- web研发模式演变史
- vs2013连接mysql配置
- 重新出发吧,少年
- java多线程模拟聊天问题