springboot中的几种scope
- 写在开始
- 技术点
- 接受方式
- 判读在线方式
- 接受数据
- 发送数据
- 敬上代码
- 入口函数
- 消息处理
- 单聊实现
- 传送门:
写在开始
上面一篇写了一篇使用WebSocket做客户端,然后服务端是socke代码实现的。传送门:webSocket和Socket实现聊天群发
本来我是打算写到一章上的,毕竟实现的都是一样的功能,后来想了想就没写在一起,主要是两个方面,
一个原因是这是另一种实现服务方式,放在一起看着有点乱。单独写也方便查阅。二是写是分开写的回家晚上写一点,不能直接在原文上写,就重新起来一个草稿,但是写完就感觉有点懒,不想整合到一块了。嘿嘿,,,
所以对开头说的不明白的同学可以先看一下前面的东西。看一下基础,事半功倍哦。
这一篇不做功能的更改,既然我们使用了WebSocket为什么不使用到底哪,我不喜欢socket的里面出现的打包请求连接数据处理和发送数据处理。可以没有问题啊。那你继续往下看吧。
首先WebSocket服务器这篇我们还是实现的6个功能:
- 单聊:可以指定人进行聊天。
- 群发:这个的意思就是当前服务器内的所有人包含自己,这个就跟一个推送效果一样。
- 开启连接(客户端):通知除自己以外的所有用户
- 关闭连接(客户端):通知除自己以外的所有用户
- 群组A:实现一个群组名字为A
- 群组B:实现一个群组名字为B
技术点
前端写法都是一样的我就不做过多的叙述了,这里只要是针对socket协议的方法进行修改成WebSocket形式。
首先我这次是把服务写成了一般处理程序进行挂载的。(有些有强迫症的小伙伴想改访问路由路径可以参考一下:mvc中路由的映射和实现IHttpHandler挂载
我在本示例就是把放在model下的一个一般处理程序,改写成了socket路径.
原来访问是:http“//http://localhost:端口号/文件夹位置/SocketServer.ashx
改完之后是:http“//http://localhost:端口号/socket/SocketServer.ashx
在实际项目中可以不暴露文件的真是路径位置,还是有点用处的。
不得不说WebSocket确实不错,比如接受发送数据解析方法都给封装好了。
接受方式
既然使用WebSocket做协议当然接受就不用用socket而是使用WebSocket啦。通过在接受到请求后获取上下文中的WebSocket。
//创建新WebSocket实例 WebSocket myClientSocket = context.WebSocket; string userId = context.QueryString["userId"];
在这里我们有一点变化就是socke用户是通过socket随机获取的,这里我修改成了页面传输。前台代码:
var userId = parseInt(Math.random() * (999999 - 100000 + 1) + 100000, 10); console.log(userId) ws = new WebSocket('ws://' + window.location.hostname + ':' + window.location.port + '/socket?userId=' + userId);
判读在线方式
WebSocket有单独的状态来进行在线的判断,不用我们自己写判断处理还是比较好的。

#region 关闭Socket处理,删除连接池 if (myClientSocket.State != WebSocketState.Open)//连接关闭 { if (ListUser.ContainsKey(userId)) ListUser.Remove(userId);//删除连接池 break; } #endregion

接受数据
WebSocket也没有辜负我们的期望,接受数据的处理也不需要我们处理的,使用ReceiveAsync方法可以得到消息字节,我们只需要定义一个字节数组段用来接受即可,例如:
ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);//定义字节数组 WebSocketReceiveResult result = await myClientSocket.ReceiveAsync(buffer, CancellationToken.None);//获得字节 string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
是不是感觉特别的方便,没有了那些乱七八糟的处理了。看着还是挺舒心的。
发送数据
既然接受数据都有单独的方法封装,发送消息没有道理没有的,是的发送使用SendAsync方法,使用形式和ReceiveAsync类似,首先定义一个字节数组段用来存放内容,例如:
ArraySegment<byte> buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes($"用户({userIdA}=>{userIdB}):{msg}")); socket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
这样子就是一个发送过程,先把要发送的字符串转换成字节数组段,然后把这个数组段使用SendAsync发送出去就可以了。
注:在上面的两个方法中我们都看到了ArraySegment这个东西,他到底是个什么哪,他是一个命名在System命名空间下的一个结构体。类似与Array数组但是他又不是数组,为什么这么说,因为他可以接受数组段,他可以只保存内容中的一部分而不是全部。就像别人说的小抽屉一样。我是把他理解成先把他放到这里当作数据缓存区,等真实发送的时候进行发送数据。WebSocketMessageType是一个枚举类型,通过F12可以看到:

// 摘要: // 指示消息类型: public enum WebSocketMessageType { // // 摘要: // 该消息是明文形式。 Text = 0, // // 摘要: // 消息采用二进制格式。 Binary = 1, // // 摘要: // 因为收到关闭的消息,接受已完成。 Close = 2 }

敬上代码
入口函数
一般处理程序中判断只接受WebSocket协议连接进入的运行:

if (context.IsWebSocketRequest) { context.AcceptWebSocketRequest(Accept); } else { }

消息处理
下面就是同意连接后的主要方法,类似上一篇写的ReceiveMessage方法(接受消息),这里的处理存在一些改动,所以我就把所有代码贴上来了。

1 #region 处理客户端连接请求 2 /// <summary> 3 /// 处理客户端连接请求 4 /// </summary> 5 /// <param name="result"></param> 6 private async Task Accept(AspNetWebSocketContext context) 7 { 8 //创建新WebSocket实例 9 WebSocket myClientSocket = context.WebSocket; 10 string userId = context.QueryString["userId"]; 11 12 try 13 { 14 15 string descUser = string.Empty;//目的用户 16 while (true) 17 { 18 if (myClientSocket.State == WebSocketState.Open) 19 { 20 ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]); 21 WebSocketReceiveResult result = await myClientSocket.ReceiveAsync(buffer, CancellationToken.None); 22 23 #region 消息处理(字符截取、消息转发) 24 try 25 { 26 #region 关闭Socket处理,删除连接池 27 if (myClientSocket.State != WebSocketState.Open)//连接关闭 28 { 29 30 if (ListUser.ContainsKey(userId)) 31 { 32 //退出 33 SignOut(userId); 34 ListUser.Remove(userId);//删除连接池 35 Debug.WriteLine("当前退出用户:" + userId); 36 } 37 break; 38 } 39 #endregion 40 string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息 41 string[] resultList = userMsg.Split(','); 42 if (resultList[0] == "login") 43 { 44 //登录 45 Login(userId); 46 #region 用户添加连接池 47 //第一次open时,添加到连接池中 48 if (!ListUser.ContainsKey(userId)) 49 ListUser.Add(userId, myClientSocket);//不存在,添加 50 else 51 if (myClientSocket != ListUser[userId])//当前对象不一致,更新 52 ListUser[userId] = myClientSocket; 53 #endregion 54 Debug.WriteLine("当前登录用户:" + userId); 55 } 56 else if (resultList[0] == "all") 57 { 58 //群发所有用户 59 GroupChat(userId, resultList[1]); 60 } 61 else if (resultList[0] == "groupA") 62 { 63 //群组发送 64 GroupChatA("groupA", userId, resultList[1]); 65 } 66 else if (resultList[0] == "groupB") 67 { 68 //群组发送 69 GroupChatA("groupB", userId, resultList[1]); 70 } 71 else 72 { 73 //单聊 74 SingleChat(userId, resultList[0], resultList[1]); 75 } 76 77 } 78 catch (Exception exs) 79 { 80 //消息转发异常处理,本次消息忽略 继续监听接下来的消息 81 } 82 #endregion 83 } 84 else 85 { 86 break; 87 } 88 }//while end 89 } 90 catch (Exception ex) 91 { 92 Console.WriteLine("Error : " + ex.ToString()); 93 } 94 } 95 #endregion

单聊实现
这里我就不把写的所有单聊,群里,实现群组方法贴上来了,实现的思路还是和以前一样,只是写法不同,我就写一个单聊作为代表示例贴上来。想看全部在下面下载源码就好了。

#region 单聊 public void SingleChat(string userIdA, string userIdB, string msg) { WebSocket socket = ListUser[userIdB]; if (socket != null) { if (socket !www.leyou2.net = null && socket.State == WebSocketState.Open) { ArraySegment<www.078881.cn byte> www.feifanyule.cn buffer =www.yongshiyule178.com new ArraySegment<byte>(Encoding.UTF8.GetBytes($"用户({userIdA}=>{userIdB}):{msg}")); socket.SendAsync(buffer, WebSocketMessageType.Binary, true, CancellationToken.None); } } } #endregion

传送门:
基础版本实现简单的websocket:实现服务端webSocket连接通讯
完善websocket实现聊天示例:WebSocket和Socket实现聊天群发
springboot中的几种scope的更多相关文章
- 补习系列(3)-springboot中的几种scope
目标 了解HTTP 请求/响应头及常见的属性: 了解如何使用SpringBoot处理头信息 : 了解如何使用SpringBoot处理Cookie : 学会如何对 Session 进行读写: 了解如何在 ...
- SpringBoot中的五种对静态资源的映射规则
目录 1. webjars:以jar包的方式引入静态资源 2./** 访问当前项目的任何资源 3.首页index.html,被" /** "映射 4.自定义图标 / favico ...
- 聊聊 SpringBoot 中的两种占位符:@*@ 和 ${*}
前言 在 SpringBoot 项目中,我们经常会使用两种占位符(有时候还会混用),它们分别是: @*@ ${*} 如果我们上网搜索「SpringBoot 的占位符 @」,大部分答案会告诉你,Spri ...
- redis(Springboot中封装整合redis,java程序如何操作redis的5种基本数据类型)
平常测试redis操作命令,可能用的是cmd窗口 操作redis,记录一下 java程序操作reids, 操作redis的方法 可以用Jedis ,在springboot 提供了两种 方法操作 Red ...
- Springboot中关于跨域问题的一种解决方法
前后端分离开发中,跨域问题是很常见的一种问题.本文主要是解决 springboot 项目跨域访问的一种方法,其他 javaweb 项目也可参考. 1.首先要了解什么是跨域 由于前后端分离开发中前端页面 ...
- springboot 中事件监听模型的一种实现
目录 定义事件本身 定义事件源 定义监听者 一.需要实现 ApplicationListener 二.使用 @EventListener 注解 测试 项目结构 前言: 事件监听模型是一种常用的设计模式 ...
- springboot成神之——mybatis在spring-boot中使用的几种方式
本文介绍mybatis在spring-boot中使用的几种方式 项目结构 依赖 WebConfig DemoApplication 方式一--@Select User DemoApplication ...
- SpringBoot中使用Spring Data Jpa 实现简单的动态查询的两种方法
软件152 尹以操 首先谢谢大佬的简书文章:http://www.jianshu.com/p/45ad65690e33# 这篇文章中讲的是spring中使用spring data jpa,使用了xml ...
- 在springboot中使用Mybatis Generator的两种方式
介绍 Mybatis Generator(MBG)是Mybatis的一个代码生成工具.MBG解决了对数据库操作有最大影响的一些CRUD操作,很大程度上提升开发效率.如果需要联合查询仍然需要手写sql. ...
随机推荐
- BZOJ 4128: Matrix
BZOJ 4128: Matrix 标签(空格分隔): OI BZOJ 大步小步 矩阵 费马小定理 Time Limit: 10 Sec Memory Limit: 128 MB Descriptio ...
- Luogu [P1248] 加工生产调度
题目链接 这个题可以贪心 我们首先想:对于所有产品,我们大致可以将其分为三类: ①.在A车间的时间要比B车间长. ②.两者一样. ③.在B车间的时间要比A车间长. 对于这三大类,怎么安排顺序? 可以看 ...
- C的xml编程-libxml2
这里主要讲述libxml2在linux下的使用. (以下内容除了linux下的安装步骤是自己写的,其余均出自http://www.blogjava.net/wxb_nudt/archive/2007/ ...
- HTML复选框checkbox默认样式修改
此方法可以将复选框的默认样式替换成任意样式.如图: 未选择: 选择时: 思路:将复选框隐藏,利用lebal元素的焦点传递特性,用lebal的样式替代复选框. 代码如下: <!DOCTYPE ht ...
- C++ 限定名称查找
限定名称查找规则实际归纳下来很简单,先对::左边的名称进行查找(遵循,限定,无限定),然后在左边查找到的(此时只查找类型名称)名字的作用域内(含内联名称空间件)查找右边出现的名字,查找到即存在(故可以 ...
- h5中的video与audio
·首先带大家熟悉一下video标签的属性方法,根据属性方法做一个小demo, HTML5支持的视频格式: Ogg 带有Theora视频编码+Ogg文件 支持的浏览器:F.O MEPG4 带有H.26 ...
- 删除Zend Studio项目
导入了过大的项目,导致很卡,且Close Project和Delete操作不了,一直无响应. 调整项目目录下的隐藏文件夹,删除对应项目: E:\www\.metadata\.plugins\org.e ...
- Head First Python (一)
建立一个数组: cast = ["Cleese","Palin","Jones","Idle"] 列出数组有多少数据项: ...
- HDU - 1973 - Prime Path (BFS)
Prime Path Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- docker 学习(2)
docker容器中安装vim ubuntu 中默认未装vim,docker run ubuntu vim 出现: container_linux.go:247: starting container ...