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.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(二)相关推荐
- WebSocket In ASP.NET Core
What Is WebSocket? WebSocket 是一种在单个 TCP 连接上进行全双工通讯的协议,是建立在TCP上.且独立的协议.在WebSocket API 中,浏览器和服务器只需要完成 ...
- 在ASP.NET Core下使用SignalR技术
一.前言 上次我们讲到过如何在ASP.NET Core中使用WebSocket,没有阅读过的朋友请参考 WebSocket in ASP.NET Core 文章 .这次的主角是SignalR它为我们提 ...
- ASP.NET Core 高级(一)【.NET 的开放 Web 接口 (OWIN)】
ASP.NET Core 中 .NET 的开放 Web 接口 (OWIN) ASP.NET Core 支持 .NET 的开放 Web 接口 (OWIN). OWIN 允许 Web 应用从 Web 服务 ...
- 为什么超过500万开发者选择了ASP.NET Core?
目录 一.What ASP.NET Core? 二.Why ASP.NET Core? 三.为什么选择这项技术? 四.ASP.NET Core的优势具体可以梳理为以下几个方面: 1.生成Web UI ...
- asp.net core 中使用 signalR(二)
asp.net core 使用 signalR(二) Intro 上次介绍了 asp.net core 中使用 signalR 服务端的开发,这次总结一下web前端如何接入和使用 signalR,本文 ...
- Asp.Net Core在线生成二维码
前言: 原先用zxing Code写过基于Winfrom的批量生成二维码工具,以及单个生成二维码工具:批量生成二维码Gihub源代码 今天尝试用QRCoder 加 Asp.Net Core 写了一个在 ...
- ASP.NET Core微服务(二)——【ASP.NET Core Swagger配置】
ASP.NET Core微服务(二)--[ASP.NET Core Swagger配置]: 环境:win10专业版+vs2019+sqlserver2014/2019 ASP.NET Core微服务( ...
- 【壹刊】Azure AD(二)调用受Microsoft 标识平台保护的 ASP.NET Core Web API (上)
---------Grant_Allen 是一位博客园新晋博主,目前开始专注于Azure方向的学习和研究,是我认识不多的.打算长时间研究Azure的群友,因此打算帮他开个专栏,同时也希望并祝愿他能一直 ...
- 从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板
标题:从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p/11155 ...
最新文章
- Java中Filter、Servlet、Listener的学习
- 飞天技术汇|阿里云推出全新开发者服务,技术赋能开发者
- [moka同学笔记]PHP操作Redis收集
- mysql常用命令--入门
- linux fg 参数,Linux的bg和fg命令简单介绍
- 三年之久的 etcd3 数据不一致 bug 分析
- php curl 批量,PHP实现的curl批量请求操作
- pgsql数据库默认配置事务类型_postgreSql最佳配置详解(connection 申请、回收策略)...
- php 安全基础 附录 A. 配置选项
- oracle设置默认值为当前时间_把锁屏密码设置成当前时间,随时间永远变动!
- 缓存DNS服务器和主从DNS服务器的快速搭建详解——续
- 毕设:后台管理系统基础模板
- 计算机网络局域网之无线局域网
- HTML页面嵌入视频无法播放的常见原因
- 《计算机科学与工程导论:基于IoT和机器人的可视化编程实践方法第2版》一2.1 工作流和可视化编程...
- Task2 数据分析 (1)
- 向日葵资深产品总监技术分享:“国民远控”如何在AD域环境下应用
- 计算机软考高级证自明评职称,IT领域唯一的国家级证书,好处多多,入手不亏...
- 编程之美 - 孟岩点评
- 【python】matplotlib.pyplot介绍