• 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.csusing 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>

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

WebSocket In ASP.NET Core(二)相关推荐

  1. WebSocket In ASP.NET Core

    What Is WebSocket?  WebSocket 是一种在单个 TCP 连接上进行全双工通讯的协议,是建立在TCP上.且独立的协议.在WebSocket API 中,浏览器和服务器只需要完成 ...

  2. 在ASP.NET Core下使用SignalR技术

    一.前言 上次我们讲到过如何在ASP.NET Core中使用WebSocket,没有阅读过的朋友请参考 WebSocket in ASP.NET Core 文章 .这次的主角是SignalR它为我们提 ...

  3. ASP.NET Core 高级(一)【.NET 的开放 Web 接口 (OWIN)】

    ASP.NET Core 中 .NET 的开放 Web 接口 (OWIN) ASP.NET Core 支持 .NET 的开放 Web 接口 (OWIN). OWIN 允许 Web 应用从 Web 服务 ...

  4. 为什么超过500万开发者选择了ASP.NET Core?

    目录 一.What ASP.NET Core? 二.Why ASP.NET Core? 三.为什么选择这项技术? 四.ASP.NET Core的优势具体可以梳理为以下几个方面: 1.生成Web UI ...

  5. asp.net core 中使用 signalR(二)

    asp.net core 使用 signalR(二) Intro 上次介绍了 asp.net core 中使用 signalR 服务端的开发,这次总结一下web前端如何接入和使用 signalR,本文 ...

  6. Asp.Net Core在线生成二维码

    前言: 原先用zxing Code写过基于Winfrom的批量生成二维码工具,以及单个生成二维码工具:批量生成二维码Gihub源代码 今天尝试用QRCoder 加 Asp.Net Core 写了一个在 ...

  7. ASP.NET Core微服务(二)——【ASP.NET Core Swagger配置】

    ASP.NET Core微服务(二)--[ASP.NET Core Swagger配置]: 环境:win10专业版+vs2019+sqlserver2014/2019 ASP.NET Core微服务( ...

  8. 【壹刊】Azure AD(二)调用受Microsoft 标识平台保护的 ASP.NET Core Web API (上)

    ---------Grant_Allen 是一位博客园新晋博主,目前开始专注于Azure方向的学习和研究,是我认识不多的.打算长时间研究Azure的群友,因此打算帮他开个专栏,同时也希望并祝愿他能一直 ...

  9. 从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板

    标题:从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p/11155 ...

最新文章

  1. Java中Filter、Servlet、Listener的学习
  2. 飞天技术汇|阿里云推出全新开发者服务,技术赋能开发者
  3. [moka同学笔记]PHP操作Redis收集
  4. mysql常用命令--入门
  5. linux fg 参数,Linux的bg和fg命令简单介绍
  6. 三年之久的 etcd3 数据不一致 bug 分析
  7. php curl 批量,PHP实现的curl批量请求操作
  8. pgsql数据库默认配置事务类型_postgreSql最佳配置详解(connection 申请、回收策略)...
  9. php 安全基础 附录 A. 配置选项
  10. oracle设置默认值为当前时间_把锁屏密码设置成当前时间,随时间永远变动!
  11. 缓存DNS服务器和主从DNS服务器的快速搭建详解——续
  12. 毕设:后台管理系统基础模板
  13. 计算机网络局域网之无线局域网
  14. HTML页面嵌入视频无法播放的常见原因
  15. 《计算机科学与工程导论:基于IoT和机器人的可视化编程实践方法第2版》一2.1 工作流和可视化编程...
  16. Task2 数据分析 (1)
  17. 向日葵资深产品总监技术分享:“国民远控”如何在AD域环境下应用
  18. 计算机软考高级证自明评职称,IT领域唯一的国家级证书,好处多多,入手不亏...
  19. 编程之美 - 孟岩点评
  20. 【python】matplotlib.pyplot介绍

热门文章

  1. phpstorm config include paths for swoole
  2. python 正则使用笔记
  3. SVN客户端--TortoiseSVN使用说明
  4. 网络工程师要如何选择?
  5. SQL Server日期函数集合
  6. 编译AjaxControlToolkit发生错误如何解决?
  7. Avalonia跨平台入门第五篇之ListBox多选
  8. 如何定位Source Generators性能问题
  9. WPF 实现3D翻转倒计时控件~
  10. 里程碑!中文版.NET官网发布,.NET开发起飞!