上一篇 - 基于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聊天室(二)的更多相关文章

  1. 基于springboot的websocket聊天室

    WebSocket入门 1.概述 1.1 Http #http简介 HTTP是一个应用层协议,无状态的,端口号为80.主要的版本有1.0/1.1/2.0. #http1.0/1.1/2.0 1.HTT ...

  2. 基于flask的网页聊天室(二)

    基于flask的网页聊天室(二) 前言 接上一次的内容继续完善,今天完成的内容不是很多,只是简单的用户注册登录,内容具体如下 具体内容 这次要加入与数据哭交互的操作,所以首先要建立相关表结构,这里使用 ...

  3. Netty入门(一)之webSocket聊天室

    一:简介 Netty 是一个提供 asynchronous event-driven (异步事件驱动)的网络应用框架,是一个用以快速开发高性能.高可靠性协议的服务器和客户端. 换句话说,Netty 是 ...

  4. 使用.NET Core和Vue搭建WebSocket聊天室

    博客地址是:https://qinyuanpei.github.io.  WebSocket是HTML5标准中的一部分,从Socket这个字眼我们就可以知道,这是一种网络通信协议.WebSocket是 ...

  5. 基于flask的网页聊天室(四)

    基于flask的网页聊天室(四) 前言 接前天的内容,今天完成了消息的处理 具体内容 上次使用了flask_login做用户登录,但是直接访问login_requare装饰的函数会报401错误,这里可 ...

  6. websocket聊天室

    目录 websocket方法总结 群聊功能 基于websocket聊天室(版本一) websocket方法总结 # 后端 3个 class ChatConsumer(WebsocketConsumer ...

  7. WebSocket聊天室demo

    根据Socket异步聊天室修改成WebSocket聊天室 WebSocket特别的地方是 握手和消息内容的编码.解码(添加了ServerHelper协助处理) ServerHelper: using ...

  8. 基于flask的网页聊天室(三)

    基于flask的网页聊天室(三) 前言 继续上一次的内容,今天完成了csrf防御的添加,用户头像的存储以及用户的登录状态 具体内容 首先是添加csrf的防御,为整个app添加防御: from flas ...

  9. 基于flask的网页聊天室(一)

    基于flask的网页聊天室(一) 基本目标 基于flask实现的web聊天室,具有基本的登录注册,多人发送消息,接受消息 扩展目标 除基本目标外添加当前在线人数,消息回复,markdown支持,历史消 ...

  10. 用Java构建一个简单的WebSocket聊天室

    前言 首先对于一个简单的聊天室,大家应该都有一定的概念了,这里我们省略用户模块的讲解,而是单纯的先说说聊天室的几个功能:自我对话.好友交流.群聊.离线消息等. 今天我们要做的demo就能帮我们做到这一 ...

随机推荐

  1. #莫队二次离线,根号分治#洛谷 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)\) ...

  2. HarmonyOS Connect “Device Partner”专场FAQ来啦!

     原文链接:https://mp.weixin.qq.com/s/mQJlAso293qgPlA1paxv5g,点击链接查看更多技术内容:     Device Partner平台是面向AIoT产业链 ...

  3. 10.1K star !牛逼了!开源技术速查表,推荐人手一份!

    1.前言 在当今信息爆炸的时代,知识的获取.整理和应用显得尤为重要.随着个人职业发展和学习需求的不断提升,搭建一个个人知识库已成为提升竞争力的关键一环.个人知识库不仅是一个信息的存储库,更是一个思维的 ...

  4. Spring Cloud OpenFeign:基于Ribbon和Hystrix的声明式服务调用

    Spring Cloud OpenFeign:基于Ribbon和Hystrix的声明式服务调用 SpringCloud学习教程 SpringCloud Spring Cloud OpenFeign 是 ...

  5. APISIX 简单的自定义插件开发步骤

    本文基于 APISIX 3.2 版本进行插件开发并运行通过. APISIX 目前开发插件比较简单,只需要编写 Lua 源代码并放到默认的插件目录下,然后通过配置文件开启插件即可,我们如果使用 Dock ...

  6. 在IDEA中新建一个SpringBoot项目(两种方法)

    方法一.使用Spring initializr快速构建 1.首先创建一个新的project,点击[File]->[New]->[Project](如果是最开始进入idea软件界面,就是点击 ...

  7. 问题排查不再愁,Nacos 上线推送轨迹功能

    简介: 微服务体系下,注册中心的调用和配置变更是家常便饭,例如阿里每天就有百万级变更.亿级推送.可是,一旦出现调用或配置异常,问题排查就成了用户最大的困惑:是注册和配置中心导致的,还是上下游业务自身的 ...

  8. 阿里云PolarDB开源数据库社区与 Tapdata 联合共建开放数据技术生态

    ​简介:近日,阿里云PolarDB开源数据库社区宣布将与 Tapdata 联合共建开放数据技术生态. 近日,阿里云PolarDB开源数据库社区宣布将与 Tapdata 联合共建开放数据技术生态.在此之 ...

  9. dotnet 给 NuGet 包加上 Aliases 别名解决类型冲突

    有时某个相同命名空间相同名字的类型被两个不同的 NuGet 包定义了,尽管这是非常少见的事情,咱需要使用到其中的一个 NuGet 包的类型,但默认情况下将会因为类型冲突而构建不通过.本文将告诉大家如何 ...

  10. 2019-11-29-WPF-Process.Start-出现-Win32Exception-异常

    title author date CreateTime categories WPF Process.Start 出现 Win32Exception 异常 lindexi 2019-11-29 10 ...