基于webapi的websocket聊天室(二)
上一篇 - 基于webapi的websocket聊天室(一)
消息超传缓冲区的问题
在上一篇中我们定义了一个聊天室WebSocketChatRoom
。但是每个游客只分配了400个字节的发言缓冲区,大概100字。
如果需要发送更多内容呢?难道直接增大缓冲区?
这是一个办法。但还有其他办法。
多次接受消息
可以多次调用ReceiveAsync
来接受消息。每次接收消息放在不同数组中,最后合并。
//WebSocketChatRoom.cs
/// <summary>
/// 多次接受消息
/// </summary>
/// <param name="client"></param>
/// <returns></returns>
public async Task<(List<byte> bytes, WebSocketMessageType MessageType)> GetBytes(WebSocket client)
{
IList<ArraySegment<byte>> byteSegments = new List<ArraySegment<byte>>();
WebSocketReceiveResult result;
do
{
ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[400]);
byteSegments.Add(buffer);
result = await client.ReceiveAsync(buffer, CancellationToken.None);
} while (result.EndOfMessage==false);
// 将所有字节连接起来
List<byte> allBytes = new List<byte>();
for (int i = 0; i < byteSegments.Count; i++)
{
var segment = byteSegments[i];
if (i== byteSegments.Count-1)
{
allBytes.AddRange(segment.Take(result.Count));
}
else
{
allBytes.AddRange(segment);
}
}
return (allBytes,result.MessageType);
}
然后调整消息循环
//WebSocketChatRoom.cs
while(!client.CloseStatus.HasValue)
{
//使用新的方法
var bytesResult = await GetBytes(client);
//广播游客发言
if (bytesResult.MessageType == WebSocketMessageType.Text)
{
CascadeMeaasge(visitor, $"{visitor.Name}: " + UTF8Encoding.UTF8.GetString(bytesResult.bytes.ToArray()));
}
}
- 缺点
由于每次接受消息都会创建新的对象来接受消息,会频繁GC。
增加默认缓存区
简单的解决这个问题,就是每个连接分配一个固定大小的默认缓存区,当这个缓存区不够的时候才临时创建新的缓存区。
改造起来也简单。
就是多增加一个参数。然后再while中第一次使用defaultBuffer,之后再创建新的buffer。
//WebSocketChatRoom.cs
/// <summary>
/// 多次接受消息
/// </summary>
/// <param name="client"></param>
/// <param name="defaultBuffer"></param>
/// <returns></returns>
public async Task<(ArraySegment<byte> bytes, WebSocketMessageType MessageType)> GetBytes(WebSocket client, byte[] defaultBuffer)
{
IList<ArraySegment<byte>> byteSegments = new List<ArraySegment<byte>>();
WebSocketReceiveResult result;
int bufferSize = 400;
do
{
if (byteSegments.Count==0)
{
byteSegments.Add(defaultBuffer);
}
else
{
ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[bufferSize]);
byteSegments.Add(buffer);
}
result = await client.ReceiveAsync(byteSegments.Last(), CancellationToken.None);
} while (result.EndOfMessage==false);
// 将所有字节连接起来
if (byteSegments.Count==1)
{
//ArraySegment是结构体,值类型,不会导致GC
return (new ArraySegment<byte>(defaultBuffer,0,result.Count), result.MessageType);
}
else
{
List<byte> allBytes = new List<byte>();
for (int i = 0; i < byteSegments.Count; i++)
{
var segment = byteSegments[i];
if (i == byteSegments.Count - 1)
{
allBytes.AddRange(segment.Take(result.Count));
}
else
{
allBytes.AddRange(segment);
}
}
var resultSegment = new ArraySegment<byte>(allBytes.ToArray());
return (resultSegment, result.MessageType);
}
}
然后调用这个方法的时候把默认缓冲区传进去即可
//WebSocketChatRoom.cs
//消息缓冲区。每个连接分配400字节,100个汉字的内存
var defaultBuffer = new byte[400];
//读数据
//消息循环
while (!client.CloseStatus.HasValue)
{
var bytesResult = await GetBytes(client, defaultBuffer);
//广播游客发言
if (bytesResult.MessageType == WebSocketMessageType.Text)
{
CascadeMeaasge(visitor, $"{visitor.Name}: " + UTF8Encoding.UTF8.GetString(bytesResult.bytes.Array,0,bytesResult.bytes.Count));
}
}
基于webapi的websocket聊天室(二)的更多相关文章
- 基于springboot的websocket聊天室
WebSocket入门 1.概述 1.1 Http #http简介 HTTP是一个应用层协议,无状态的,端口号为80.主要的版本有1.0/1.1/2.0. #http1.0/1.1/2.0 1.HTT ...
- 基于flask的网页聊天室(二)
基于flask的网页聊天室(二) 前言 接上一次的内容继续完善,今天完成的内容不是很多,只是简单的用户注册登录,内容具体如下 具体内容 这次要加入与数据哭交互的操作,所以首先要建立相关表结构,这里使用 ...
- Netty入门(一)之webSocket聊天室
一:简介 Netty 是一个提供 asynchronous event-driven (异步事件驱动)的网络应用框架,是一个用以快速开发高性能.高可靠性协议的服务器和客户端. 换句话说,Netty 是 ...
- 使用.NET Core和Vue搭建WebSocket聊天室
博客地址是:https://qinyuanpei.github.io. WebSocket是HTML5标准中的一部分,从Socket这个字眼我们就可以知道,这是一种网络通信协议.WebSocket是 ...
- 基于flask的网页聊天室(四)
基于flask的网页聊天室(四) 前言 接前天的内容,今天完成了消息的处理 具体内容 上次使用了flask_login做用户登录,但是直接访问login_requare装饰的函数会报401错误,这里可 ...
- websocket聊天室
目录 websocket方法总结 群聊功能 基于websocket聊天室(版本一) websocket方法总结 # 后端 3个 class ChatConsumer(WebsocketConsumer ...
- WebSocket聊天室demo
根据Socket异步聊天室修改成WebSocket聊天室 WebSocket特别的地方是 握手和消息内容的编码.解码(添加了ServerHelper协助处理) ServerHelper: using ...
- 基于flask的网页聊天室(三)
基于flask的网页聊天室(三) 前言 继续上一次的内容,今天完成了csrf防御的添加,用户头像的存储以及用户的登录状态 具体内容 首先是添加csrf的防御,为整个app添加防御: from flas ...
- 基于flask的网页聊天室(一)
基于flask的网页聊天室(一) 基本目标 基于flask实现的web聊天室,具有基本的登录注册,多人发送消息,接受消息 扩展目标 除基本目标外添加当前在线人数,消息回复,markdown支持,历史消 ...
- 用Java构建一个简单的WebSocket聊天室
前言 首先对于一个简单的聊天室,大家应该都有一定的概念了,这里我们省略用户模块的讲解,而是单纯的先说说聊天室的几个功能:自我对话.好友交流.群聊.离线消息等. 今天我们要做的demo就能帮我们做到这一 ...
随机推荐
- #莫队二次离线,根号分治#洛谷 5398 [Ynoi2018] GOSICK
题目 \(m\) 组询问求 \(\sum_{l\leq i,j\leq r}[a_i\bmod a_j==0],n,m,a_i\leq 5\times 10^5\) 分析 设 \(f(l,r,x)\) ...
- HarmonyOS Connect “Device Partner”专场FAQ来啦!
原文链接:https://mp.weixin.qq.com/s/mQJlAso293qgPlA1paxv5g,点击链接查看更多技术内容: Device Partner平台是面向AIoT产业链 ...
- 10.1K star !牛逼了!开源技术速查表,推荐人手一份!
1.前言 在当今信息爆炸的时代,知识的获取.整理和应用显得尤为重要.随着个人职业发展和学习需求的不断提升,搭建一个个人知识库已成为提升竞争力的关键一环.个人知识库不仅是一个信息的存储库,更是一个思维的 ...
- Spring Cloud OpenFeign:基于Ribbon和Hystrix的声明式服务调用
Spring Cloud OpenFeign:基于Ribbon和Hystrix的声明式服务调用 SpringCloud学习教程 SpringCloud Spring Cloud OpenFeign 是 ...
- APISIX 简单的自定义插件开发步骤
本文基于 APISIX 3.2 版本进行插件开发并运行通过. APISIX 目前开发插件比较简单,只需要编写 Lua 源代码并放到默认的插件目录下,然后通过配置文件开启插件即可,我们如果使用 Dock ...
- 在IDEA中新建一个SpringBoot项目(两种方法)
方法一.使用Spring initializr快速构建 1.首先创建一个新的project,点击[File]->[New]->[Project](如果是最开始进入idea软件界面,就是点击 ...
- 问题排查不再愁,Nacos 上线推送轨迹功能
简介: 微服务体系下,注册中心的调用和配置变更是家常便饭,例如阿里每天就有百万级变更.亿级推送.可是,一旦出现调用或配置异常,问题排查就成了用户最大的困惑:是注册和配置中心导致的,还是上下游业务自身的 ...
- 阿里云PolarDB开源数据库社区与 Tapdata 联合共建开放数据技术生态
简介:近日,阿里云PolarDB开源数据库社区宣布将与 Tapdata 联合共建开放数据技术生态. 近日,阿里云PolarDB开源数据库社区宣布将与 Tapdata 联合共建开放数据技术生态.在此之 ...
- dotnet 给 NuGet 包加上 Aliases 别名解决类型冲突
有时某个相同命名空间相同名字的类型被两个不同的 NuGet 包定义了,尽管这是非常少见的事情,咱需要使用到其中的一个 NuGet 包的类型,但默认情况下将会因为类型冲突而构建不通过.本文将告诉大家如何 ...
- 2019-11-29-WPF-Process.Start-出现-Win32Exception-异常
title author date CreateTime categories WPF Process.Start 出现 Win32Exception 异常 lindexi 2019-11-29 10 ...