首页 > 其他分享 >基于webapi的websocket聊天室(二)

基于webapi的websocket聊天室(二)

时间:2024-05-12 10:53:54浏览次数:11  
标签:webapi Count 聊天室 websocket client byteSegments result new allBytes

上一篇 - 基于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,Count,聊天室,websocket,client,byteSegments,result,new,allBytes
From: https://www.cnblogs.com/ggtc/p/18187282

相关文章

  • SpringBoot3集成WebSocket
    标签:WebSocket,Session,Postman。一、简介WebSocket通过一个TCP连接在客户端和服务器之间建立一个全双工、双向的通信通道,使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据,在WebSocket的API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创......
  • 基于webapi的websocket聊天室
    上一次我已经讲了在webapi主机上面加入websocket中间件。这次就更进一步,搭建一个websocket局域网聊天室。传送门-->webapi添加添加websocket中间件聊天室websocket通信其实和win32api里面的消息循环差不多,只不过一个消息来自操作系统,一个来自网络。但核心都是一个阻塞的while......
  • 实时行情数据源接口websocket接入方法
    ​支持如下产品对接:外汇、国际期货、国内期货、国际金银、数字货币、股指期货、美股、印度股、港股、台股、A股产品代码获取地址:http://39.107.99.235:1008/market/market.php产品代码:比特币btcusdt以太坊ethusdt恒指期货HSI德指期货DAX英镑美元fx_sgbpusd欧......
  • 分享一个使用python调用websocket获取实时行情数据的方法
    这个站点可以获取:外汇、国际期货、国内期货、贵金属、能源、虚拟货币、股指期货、美股、台股、港股、印度股、A股、ETF等以下是Python的连接demo,可以参考下。同时也支持其他后端语言的连接,PHP、Java等。获取品种地址:http://39.107.99.235:1008/market/market.phpimportj......
  • 【转】[C#] WebAPI 防止并发调用二(冥等性)
    来自:阿里的通义灵码使用幂等性设计来防止C#WebAPI方法的并发调用是一种推荐的方法,因为它不会阻塞其他请求,而是确保多次调用同一个操作会产生相同的结果。这里有一个简单的示例,说明如何在WebAPI控制器中实现幂等性的API:usingSystem;usingSystem.Web.Http;usingSystem.Lin......
  • 【转】[C#] WebAPI 防止并发调用一(锁)
    来源:阿里的通义灵码在C#WebAPI中,如果你想要使用锁来防止并发调用,你可以使用System.Threading.Mutex或System.Threading.Lock来实现。但是,这种方法通常不推荐,因为它可能会导致请求阻塞,从而影响整个Web服务的性能。在Web环境中,更好的做法是使用幂等性设计或数据库事务来处理并发......
  • Qt开发websocket服务
     Qt自带的有网络编程模块,需要再pro文件加上 websockets#pro文件QT+=coreguiwebsockets .h#ifndefWIDGET_H#defineWIDGET_H#include<QWidget>#include<QWebSocketServer>#include<QWebSocket>#include<QDebug>QT_BEGIN_NAMESPACEna......
  • 实时股票数据API接口websocket接入方法
    一、使用websocket的协议提升传输速度实时金融股票API接口对于投资者和交易员来说至关重要。通过使用WebSocket接入方法,可以轻松获取实时金融股票API接口的数据并及时做出决策。WebSocket是一种高效的双向通信协议,它允许数据的实时推送,避免了不断的轮询请求。这种接入方法具有多......
  • websocket-sharp:.NET平台上的WebSocket客户端与服务器开源库
    1.简介:websocket-sharp提供WebSocket客户端和服务器库,基于C#开发的,并遵循WebSocket协议规范,使得开发人员能够轻松地在.NET应用程序中实现WebSocket通信。https://github.com/sta/websocket-sharpwebsocket-sharp特色功能有:1、简洁易用的API:提供清晰且直观的API接......
  • SpringBoot集成WebSocket
    SpringBoot集成WebSocket1.引jar包<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency&......