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

基于webapi的websocket聊天室

时间:2024-05-11 22:08:54浏览次数:28  
标签:webapi 聊天室 websocket 游客 client context public

上一次我已经讲了在webapi主机上面加入websocket中间件。
这次就更进一步,搭建一个websocket局域网聊天室。
传送门-->webapi添加添加websocket中间件

聊天室

websocket通信其实和win32api里面的消息循环差不多,只不过一个消息来自操作系统,一个来自网络。
但核心都是一个阻塞的while循环,在循环中处理各种消息。
由于搭建聊天室代码多一点,我就把中间件单独写一个类,而不是用lambadu委托在program里面直接写了。

  • 聊天室成员
    游客对象可以是单纯的WebSocket对象,也可以是更复杂的对象。但我们还需要为游客命名等,所以采用自定义一个游客类来代表游客信息。
//RoomVisitor.cs

public class RoomVisitor
{
    /// <summary>
    /// 网络连接
    /// </summary>
    public WebSocket Web { get; set; }
    /// <summary>
    /// 名字
    /// </summary>
    public string Name { get; set; }
    /// <summary>
    /// ID
    /// </summary>
    public string Id { get; set; }
}

我暂时就考虑这些字段。其实还有,比如前面已经添加了身份认证的中间件,可以取得其他信息。但是目前为了简单,先不考虑认证的问题。不考虑会员,只考虑游客。

  • 聊天室对象
    在初始阶段。我们先不考虑从那么复杂,不考虑多少个聊天室的情况,就考虑单聊天室。这样我们就可以使用单例模式进行依赖注入。
/// <summary>
/// 聊天室
/// </summary>
public class WebSocketChatRoom
{
    /// <summary>
    /// 成员
    /// </summary>
    public ConcurrentDictionary<string, RoomVisitor> clients=new ConcurrentDictionary<string, RoomVisitor>();

    public WebSocketChatRoom()
    {
        
    }
}
//program.cs

//添加聊天室服务
builder.Services.AddSingleton<WebSocketChatRoom>();

聊天室功能

为了不那么单调,我们只定义聊天室三个最简单的功能。

  • 上线通知
  • 发言广播
  • 下线通知

消息循环条件

在win32api中消息循环是while(有消息),直到接收到窗体关闭消息,退出循环,程序未关闭。
websocket类似。需要while(client.CloseStatus.HasValue==false),连接未关闭时一直循环。
当然,这是个阻塞式循环

上线通知和下线通知

这两个功能倒是简单。在websocket连接建立时和连接关闭时广播一条消息就行。
也就是在进入消息循环前退出消息循环后

//游客加入聊天室
var visitor = new RoomVisitor() { Id= System.Guid.NewGuid().ToString("N"), Name = $"游客_{clients.Count + 1}", Web = client };
while(client.CloseStatus.HasValue==false)
{
	//...
}
//广播游客退出
CascadeMeaasge(visitor,$"{visitor.Name}退出聊天室");
clients.TryRemove(visitor.Id, out RoomVisitor v);
//关闭连接...
await client.CloseAsync(
    client.CloseStatus!.Value,
    client.CloseStatusDescription,
    CancellationToken.None);

发言广播

在收到消息时,遍历聊天室成员,依次转发这条消息。
当然,还可以加一些处理。比如添加发言人名字,时间等。

  • 首先要定义广播方法,CascadeMeaasge
public void CascadeMeaasge(RoomVisitor visitor, string message)
{
    foreach (var other in clients)
    {
        //不对发言者广播
        if (visitor!=null)
        {
            if (other.Key == visitor.Id)
            {
                continue;
            }
        }
        //转发内容
        var buffer = Encoding.UTF8.GetBytes(message);
        if (other.Value.Web.State==WebSocketState.Open)
        {
            other.Value.Web.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
        }
    }
}
  • 收到消息时广播转发
//消息缓冲区。每个连接分配400字节,100个汉字的内存
var minimumBuffer=new byte[400];
while(!client.CloseStatus.HasValue)
{

    WebSocketReceiveResult result = await client.ReceiveAsync(new ArraySegment<byte>(minimumBuffer), CancellationToken.None);
    //广播游客发言
    if (result.MessageType == WebSocketMessageType.Text)
    {
        CascadeMeaasge(visitor, $"{visitor.Name}: "+UTF8Encoding.UTF8.GetString(minimumBuffer,0, result.Count));
    }
}

聊天室的核心功能就完成了,实在是没几行代码。

添加中间件处理websocket连接

websocket连接很多,不一定都是要进入聊天室。我们使用/chat路径来路由到聊天室。

  • 中间件定义
//WebSocketChatRoomMiddleware.cs

public class WebSocketChatRoomMiddleware
{
    private readonly RequestDelegate _next;

    public WebSocketChatRoomMiddleware(RequestDelegate next, Func<WebSocketChatRoom> handler)
    {
        _next = next;
        Handler = handler;
    }

    public Func<WebSocketChatRoom> Handler { get; }

    public async Task InvokeAsync(HttpContext context)
    {
        await _next(context);
        if (context.Request.Path=="/chat")
        {
            WebSocket client = await context.WebSockets.AcceptWebSocketAsync();
            await Handler().HandleContext(context, client);
        }

    }
}

我们使用MapWhen单独给websocket连接做一个管道分支,区别于http处理流程。只有websocket连接才会进入这个分支。
注意授权中间件,如果没做,可以删掉。

//WebSocketChatRoomMiddleware.cs

public static class WebSocketChatRoomMiddlewareExtensions
{
    public static WebApplication UseWebSocketChatRoomMiddleware(this WebApplication builder)
    {
        //建立websocket分支
        builder.MapWhen(c => c.WebSockets.IsWebSocketRequest, appbuilder =>
        {
            //授权
            appbuilder.Use(async (context, next) =>
            {
                if (context.User.Identity.IsAuthenticated)
                    await next(context);
                else
                    context.Response.StatusCode = StatusCodes.Status403Forbidden;
            })
            //连接
            .UseMiddleware<WebSocketChatRoomMiddleware>(new Func<WebSocketChatRoom>(() => 
            {
                return appbuilder.ApplicationServices.GetRequiredService<WebSocketChatRoom>();
            }));
        });
        return builder;
    }
}
  • 添加中间件
//program.cs

//调用了此终结点才能判断连接请求是不是ws请求,会让ws连接的context.WebSockets.IsWebSocketRequest变成true
app.UseWebSockets();
//使用我们定义的中间件
app.UseWebSocketChatRoomMiddleware();

聊天测试

客户端就直接用api请求工具吧,懒得写了。我使用了ApiPost来测试。
我定义了三个游客来测试广播功能

  • 游客定义

image

  • 测试步骤

  1. 游客1、游客2、游客3依次连接聊天室。查看加入聊天室的广播信息。
  2. 游客1、游客2、游客3依次发言。查看发言广播。
  3. 游客1、游客2、游客3依次退出聊天室。查看退出聊天室广播信息。
    image

image

image

image

image

标签:webapi,聊天室,websocket,游客,client,context,public
From: https://www.cnblogs.com/ggtc/p/18185414

相关文章

  • 实时行情数据源接口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&......
  • websocket
    websocket,web版的socket原web中:http协议,无状态&短链接客户端主动连接服务器客户端向服务器发送消息,服务器收到返回数据客户端收到数据断开连接https一些+对数据进行加密。我们在开发过程中想要保留一些状态信息,基于cookie来做现在支持:http协议。一次请求一次响......
  • web server apache tomcat11-31-websocket
    前言整理这个官方翻译的系列,原因是网上大部分的tomcat版本比较旧,此版本为v11最新的版本。开源项目从零手写实现tomcatminicat别称【嗅虎】心有猛虎,轻嗅蔷薇。系列文章webserverapachetomcat11-01-官方文档入门介绍webserverapachetomcat11-02-setup启动web......