WebSocket In ASP.NET Core(二)

  • Introduce

  上篇博文中,介绍了WebSocket的基本原理,以及一个简单的Demo用来对其有一个大致的认识。这篇博文讲的是我们平常在网站上可能会经常遇到的——实时聊天,本文就是来讲在.NET-Core使用WebSocket来实现一个“乞丐版”的在线实时聊天Demo。

关键词Middleware,Real-Time,WebSocket

Before You Read.

 这个和我们上一篇博文中Demo 有何不同的呢?有何共同之处呢?

 相同的点是,都是网页作为客户端,使用JavaScript来发送和接收请求,.NET-Core 服务端接收到请求,发送该请求给客户端。

不同的地方呢,就像我下面这张图这样:

一次同时有多个客户端在,所以应该很清楚,我们只要在上面例子的基础上,对当前的已存在的Socket进行轮询,发送回应即可达到我们想要的效果。

Create WebSocket Middleware

 在上个Demo的例子中,我们直接在Startup 的Configure 中直接写接受WebSocket请求。这次我们换成Middleware形式来处理。在写Middleware之前,在之前的介绍中,我们知道,需要有多个WebSocket,那么肯定需要一些对WebSocket 的Get/Set 处理。我简单的写了一个下面WebScoket Manger Class

//WebSocketManager.cs

using System;

using System.Collections.Concurrent;

using System.Collections.Generic;

using System.Linq;

using System.Net.WebSockets;

using System.Text;

using System.Threading;

using System.Threading.Tasks;


namespace WebSocketManage

{

    public class WSConnectionManager

    {

        private static ConcurrentDictionary<string, WebSocket> _socketConcurrentDictionary = new ConcurrentDictionary<string, WebSocket>();


        public void AddSocket(WebSocket socket)

        {

            _socketConcurrentDictionary.TryAdd(CreateGuid(), socket);

        }


        public async Task RemoveSocket(WebSocket socket)

        {

            _socketConcurrentDictionary.TryRemove(GetSocketId(socket), out WebSocket aSocket);


            await aSocket.CloseAsync(

                closeStatus: WebSocketCloseStatus.NormalClosure,

                statusDescription: "Close by User",

                cancellationToken: CancellationToken.None).ConfigureAwait(false);

        }


        public string GetSocketId(WebSocket socket)

        {

            return _socketConcurrentDictionary.FirstOrDefault(k => k.Value == socket).Key;

        }


        public ConcurrentDictionary<string, WebSocket> GetAll()

        {

            return _socketConcurrentDictionary;

        }


        public string CreateGuid()

        {

            return Guid.NewGuid().ToString();

        }

    }

}

上面主要是对WebSocket 进行了简单的存取操作进行了封装。下面也把WebSocket 的Send 和Recieve 操作进行了封装。

using System;

using System.Collections.Generic;

using System.IO;

using System.Net.WebSockets;

using System.Text;

using System.Threading;

using System.Threading.Tasks;


namespace WebSocketManage

{

    public class WSHandler

    {

        protected WSConnectionManager _wsConnectionManager;


        public WSHandler(WSConnectionManager wSConnectionManager)

        {

            _wsConnectionManager = wSConnectionManager;

        }


        public async Task SendMessageAsync(

            WebSocket socket,

            string message,

            CancellationToken cancellationToken = default(CancellationToken))

        {

            var buffer = Encoding.UTF8.GetBytes(message);

            var segment = new ArraySegment<byte>(buffer);


            await socket.SendAsync(segment, WebSocketMessageType.Text, true, cancellationToken);

        }

        public async Task<string> RecieveAsync(WebSocket webSocket, CancellationToken cancellationToken)

        {

            var buffer = new ArraySegment<byte>(new byte[1024 * 8]);

            using (var ms = new MemoryStream())

            {

                WebSocketReceiveResult result;

                do

                {

                    cancellationToken.ThrowIfCancellationRequested();


                    result = await webSocket.ReceiveAsync(buffer, cancellationToken);

                    ms.Write(buffer.Array, buffer.Offset, result.Count);

                }

                while (!result.EndOfMessage);


                ms.Seek(0, SeekOrigin.Begin);

                if (result.MessageType != WebSocketMessageType.Text)

                {

                    return null;

                }


                using (var reader = new StreamReader(ms, Encoding.UTF8))

                {

                    return await reader.ReadToEndAsync();

                }

            }

        }

    }

}

有了上面两个辅助类之后,接下来就可以写我们自己的RealTimeWebSocketMiddlerware 了,


using Microsoft.AspNetCore.Http;

using System;

using System.Collections.Generic;

using System.IO;

using System.Net.WebSockets;

using System.Text;

using System.Threading;

using System.Threading.Tasks;

using WebSocketManage;


namespace Robert.Middleware.WebSockets

{

    public class RealTimeWSMiddleware

    {

        private readonly RequestDelegate _next;

        private WSConnectionManager _wSConnectionManager { get; set; }

        private WSHandler _wsHanlder { get; set; }


        public RealTimeWSMiddleware(

            RequestDelegate next,

            WSConnectionManager wSConnectionManager,

            WSHandler wsHandler)

        {

            _next = next;

            _wSConnectionManager = wSConnectionManager;

            _wsHanlder = wsHandler;

        }


        public async Task Invoke(HttpContext httpContext)

        {

            if (httpContext.WebSockets.IsWebSocketRequest)

            {

                var cancellationToken = httpContext.RequestAborted;

                var currentWebSocket = await httpContext.WebSockets.AcceptWebSocketAsync();

                _wSConnectionManager.AddSocket(currentWebSocket);


                while (true)

                {

                    if (cancellationToken.IsCancellationRequested) break;

                    var response = await _wsHanlder.ReceiveAsync(currentWebSocket, cancellationToken);


                    if (string.IsNullOrEmpty(response) && currentWebSocket.State != WebSocketState.Open) break;


                    foreach (var item in _wSConnectionManager.GetAll())

                    {

                        if (item.Value.State == WebSocketState.Open)

                        {

                            await _wsHanlder.SendMessageAsync(item.Value, response, cancellationToken);

                        }

                        continue;

                    }

                }


                await _wSConnectionManager.RemoveSocket(currentWebSocket);

            }

            else

            {

                await _next(httpContext);

            }

        }

    }

}

有了上面两个辅助类之后,接下来就可以写我们自己的RealTimeWebSocketMiddlerware 了,

using Microsoft.AspNetCore.Http;

using System;

using System.Collections.Generic;

using System.IO;

using System.Net.WebSockets;

using System.Text;

using System.Threading;

using System.Threading.Tasks;

using WebSocketManage;


namespace Robert.Middleware.WebSockets

{

    public class RealTimeWSMiddleware

    {

        private readonly RequestDelegate _next;

        private WSConnectionManager _wSConnectionManager { get; set; }

        private WSHandler _wsHanlder { get; set; }


        public RealTimeWSMiddleware(

            RequestDelegate next,

            WSConnectionManager wSConnectionManager,

            WSHandler wsHandler)

        {

            _next = next;

            _wSConnectionManager = wSConnectionManager;

            _wsHanlder = wsHandler;

        }


        public async Task Invoke(HttpContext httpContext)

        {

            if (httpContext.WebSockets.IsWebSocketRequest)

            {

                var cancellationToken = httpContext.RequestAborted;

                var currentWebSocket = await httpContext.WebSockets.AcceptWebSocketAsync();

                _wSConnectionManager.AddSocket(currentWebSocket);


                while (true)

                {

                    if (cancellationToken.IsCancellationRequested) break;

                    var response = await _wsHanlder.ReceiveAsync(currentWebSocket, cancellationToken);


                    if (string.IsNullOrEmpty(response) && currentWebSocket.State != WebSocketState.Open) break;


                    foreach (var item in _wSConnectionManager.GetAll())

                    {

                        if (item.Value.State == WebSocketState.Open)

                        {

                            await _wsHanlder.SendMessageAsync(item.Value, response, cancellationToken);

                        }

                        continue;

                    }

                }


                await _wSConnectionManager.RemoveSocket(currentWebSocket);

            }

            else

            {

                await _next(httpContext);

            }

        }

    }

}


 其实到这里,核心部分已经讲完了,接下来就是页面显示,发现信息,交互的问题了。在客户端还是像上篇文章中的一样,直接使用 JavaScript发送WebScoket请求。

 下面主要演示一下效果,在上篇博文的基础上,加上了用户名。

<script>$(function () {var protocol = location.protocol === "https:" ? "wss:" : "ws:";var Uri = protocol + "//" + window.location.host + "/ws";var socket = new WebSocket(Uri);socket.onopen = e => {console.log("socket opened", e);};socket.onclose = function (e) {console.log("socket closed", e);};//function to receive from server.socket.onmessage = function (e) {console.log("Message:" + e.data);$('#msgs').append(e.data + '<br />');};socket.onerror = function (e) {console.error(e.data);};});</script>

当写好了页面文件后,运行站点。最终运行的效果图,界面以实用为主,不求美观。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/323508.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

不支持POST请求方法,支持以下GET、

大家好&#xff0c;我是雄雄。 刚刚在用**FeignClient**注解的时候&#xff0c;报了个错&#xff0c;不支持POST请求方法&#xff0c;支持以下GET、。 字面意思上看&#xff0c;好像是让把请求方式从post改成get. 但是&#xff0c;我检查了下我的代码&#xff0c;get提交方式…

P3701 -「伪模板」主席树【网络流,最大流】

正题 评测记录:https://www.luogu.org/recordnew/lists?uid52918&pidP3701 题目大意 给出若干个人的克制关系 给出两边每个人的种类和血量。当两个人pkpkpk后&#xff0c;双方各−1hp-1hp−1hp&#xff0c;同一边的YYYYYYYYY可以给每个同一方的J1hpJ\ 1hpJ 1hp&#xf…

微服务如何实现各个模块之间相互调用

大家好&#xff0c;我是雄雄&#xff0c;现在是:2022年8月23日21:08:53 前言 在做微服务项目时&#xff0c;我们可能都会遇到这样的情况&#xff0c;那就是A服务需要调用B服务中的某个接口&#xff0c;那有这样的需求时&#xff0c;我们应该怎么处理呢&#xff1f; 实现 使用…

2017年秋招美团Java程序员开发,看我如何拿到offer

转载自 2017年秋招美团Java程序员开发&#xff0c;看我如何拿到offer 本人是一名本科毕业非计算机专业的程序员&#xff0c;面了阿里&#xff0c;结果没过&#xff0c;最后面上了美团&#xff0c;热乎乎的面经&#xff0c;昨天面的美团&#xff0c;虽然面完了HR面&#xff0c…

ASP.NET Core 运行原理剖析

1.1. 概述在ASP.NET Core之前&#xff0c;ASP.NET Framework应用程序由IIS加载。Web应用程序的入口点由InetMgr.exe创建并调用托管。以初始化过程中触发HttpApplication.Application_Start()事件。开发人员第一次执行代码的机会是处理Application_StartGlobal.asax中的事件。在…

使用wxJava开发微信服务(公众)号,实现新建素材的功能

大家好&#xff0c;我是雄雄。 前言 微信服务&#xff08;公众号&#xff09;号开发&#xff0c;前面已经整理过了几篇文章了&#xff0c;如下&#xff1a; java实现微信服务&#xff08;公众&#xff09;号用户关注时&#xff0c;获取openid&#xff0c;安全模式下的加密解密…

经典指针程序互换(一)

#include<stdio.h> huan(int *p,int *q){int t;t*p;*p*q;*qt;}int main(){ int a3,b10; huan(&a,&b);printf("%d %d",a,b); }这里我最疑惑的是不是改变*p的值就改变了a的值&#xff0c;为此&#xff0c;我专门敲了段代码&#xff0c;验证一下 #inclu…

Spring MVC 到底是如何工作的

转载自 Spring MVC 到底是如何工作的 这篇文章将深入探讨Spring框架的一部分——Spring Web MVC的强大功能及其内部工作原理。 这篇文章的源代码可以在GitHub上找到。 项目安装 在本文中&#xff0c;我们将使用最新、最好的Spring Framework 5。我们将重点介绍Spring的经典…

Entity Framework中的字符串插值引发担忧

将内插字符串&#xff08;Interpolated Strings&#xff09;自动地转化为参数化SQL语句&#xff0c;这是Entity Framework Core 2提供的一个新特性。虽然该特性从设计上是为了避免出现SQL语句编写上的问题&#xff0c;但是有人担心这会导致更多的SQL注入攻击。下面给出一个正确…

jeecg-boot集成xxl-job调度平台,每秒/每分钟/手动都能执行成功,但是设置固定时间不触发?

大家好&#xff0c;我是雄雄。 目录 这里写目录标题目录bug说明解决bug的过程解决方法结论今天在用jeecg-boot集成了的xxl-job的时候&#xff0c;遇到了个奇葩的问题&#xff08;其实一点都不奇葩&#xff09;&#xff0c;投入了几个人&#xff0c;一起看这个问题&#xff0c;看…

nssl1156-今天你AK了吗?【康托展开,高精度,二分答案,树状数组】

正题 题目大意 求n个数的全排列的第k个。 解题思路 首先康拓逆展开 ∑ii<nxi(n−i)!\sum^{i<n}_i x_i(n-i)!∑ii<n​xi​(n−i)! 求每个时候第xxx大的数 然后因为n(n−1)!n!n(n-1)!n!n(n−1)!n! so我们可以直接用余数 这是n3n3n3时是序列&#xff0c;我们可以发现我…

指针数组(二)

#include<stdio.h> void f(int *pA,int len){int i;for(i0;i<len;i){printf("%d",*(pAi)); }printf("\n");}main(){int a[5]{1,2,3,4,5};int b[4]{5,4,3,2};f(a,5);f(b,3);} 我想不用指针直接用函数来输出&#xff0c;看下 #include<stdio.h…

use of CGLib-based proxies by setting proxyTargetClass=true on @EnableAsync and/or @EnableCaching

大家好&#xff0c;我是雄雄。 今天在做异步的时候&#xff0c;报了个错&#xff0c;错误信息如下&#xff1a; Error starting ApplicationContext. To display the conditions report re-run your application with ‘debug’ enabled. 2022-08-25 17:58:30.784 [main] ERRO…

.NET Core 使用RabbitMQ

RabbitMQ简介AMQP&#xff0c;即Advanced Message Queuing Protocol&#xff0c;高级消息队列协议&#xff0c;是应用层协议的一个开放标准&#xff0c;为面向消息的中间件设计。消息中间件主要用于组件之间的解耦&#xff0c;消息的发送者无需知道消息使用者的存在&#xff0c…

冒泡法排序

#include<stdio.h> main(){int i,j,t,a[]{2,5,8,6,15,89,55,46};for(i0;i<7;i){for(j0;j<7-i;j){if(a[j]>a[j1]){ta[j1];a[j1]a[j];a[j]t;} }}for(i0;i<8;i){printf("%d ",a[i]);} } 刚开始还以为敲的有bug&#xff0c;数组里有五六位后排序就…

十分钟快速了解 ES6 Promise

转载自 十分钟快速了解 ES6 Promise 什么是Promise Promise最早由社区提出并实现&#xff0c;典型的一些库有Q&#xff0c;when&#xff0c; bluebird等&#xff1b;它们的出现是为了更好地解决JavaScript中异步编程的问题&#xff0c;传统的异步编程最大的特点就是地狱般的回…

揭示.NET Core和.NET Standard

作为.NET家族的最新成员&#xff0c;有很多关于.NET Core和.NET Standard的误解&#xff0c;以及它们于.NET Framework之间的区别。在这篇文章&#xff0c;我会准确的解释他们究竟是什么&#xff0c;并看看何时应选择哪一个。在详细介绍之前&#xff0c;首先查看.NET的结构图&a…

使用wxjava实现发表内容、预览信息以及推送文章

大家好&#xff0c;我是雄雄。 文章目录前言保存草稿的方法获取草稿箱列表根据media_id获取草稿箱信息给指定人发送预览文章推送文章&#xff08;按照标签推送&#xff09;前言 今天分享的内容有如下几个&#xff1a; 保存草稿根绝media_id会哦去草稿箱的信息发表内容&#x…

指针数组(三)

#include<stdio.h>void g(int *pArr,int len){pArr[2]88;pArr[4]88;}void f(){int a[]{1,2,3,5,9},i;g(a,5);for(i0;i<5;i){printf("%d\t",a[i]);}}main(){f();}利用指针改变数组里的内容和内容

spring cloud+dotnet core搭建微服务架构:服务发现(二)

前言上篇文章《手把手教你使用spring clouddotnet core搭建微服务架构&#xff1a;服务治理&#xff08;-&#xff09;》实际上只讲了服务治理中的服务注册&#xff0c;服务与服务之间如何调用呢&#xff1f;传统的方式&#xff0c;服务A调用服务B&#xff0c;那么服务A访问的是…