WebSocket In ASP.NET Core(二)
.NET-Core Series
- Server in ASP.NET-Core
- DI in ASP.NET-Core
- Routing in ASP.NET-Core
- Error Handling in ASP.NET-Core
- WebSocket in ASP.NET-Core(一)
- WebSocket in ASP.NET-Core(二)
- To Be Continue...
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);
}
}
}
}
其实到这里,核心部分已经讲完了,接下来就是页面显示,发现信息,交互的问题了。在客户端还是像上篇文章中的一样,直接使用 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
一.WebSocket WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算) 首先HTTP有1.1和1.0 ...
- WebSocket In ASP.NET Core(一)
.NET-Core Series Server in ASP.NET-Core DI in ASP.NET-Core Routing in ASP.NET-Core Error Handling in ...
- K8S+GitLab-自动化分布式部署ASP.NET Core(二) ASP.NET Core DevOps
一.介绍 前一篇,写的K8S部署环境的文章,简单的介绍下DevOps(Development和Operations的组合词),高效交付, 自动化流程,来减少软件开发人员和运维人员的沟通.Martin ...
- asp.net core 二 Nginx Supervisor 负载,监听
ASP.NET Core负载均衡集群搭建(CentOS7+Nginx+Supervisor+Kestrel) asp.net core在linux运行下,一但命令行退出 ...
- ASP.NET Core (二):入门
上一篇:ASP.NET Core(一):简介 下一篇:(待续) 英文原版:Getting Started 1. 安装 .NET Core 2. 创建 .NET Core 项目 在命令提示符窗口输入命令 ...
- asp.net core系列 70 即时通迅-WebSocket+Redis发布订阅
一.概述 在asp.net core 中可以用WebSocket 或asp.net core SignalR来开发即时通迅.在项目中由于开发前后端分离,对于SignalR前端技术人员不想依赖juqer ...
- 使用websocket连接(对接)asp.net core signalr
使用通用websocket连接asp.net core signalr 一.背景介绍 signalr的功能很强大,可以为我们实现websocket服务端节省不少的时间.但是可能由于不同的环境,我们在对 ...
- 在ASP.NET Core下使用SignalR技术
一.前言 上次我们讲到过如何在ASP.NET Core中使用WebSocket,没有阅读过的朋友请参考 WebSocket in ASP.NET Core 文章 .这次的主角是SignalR它为我们提 ...
- ASP.NET Core (一):简介
下一篇:ASP.NET Core(二):入门 英文原版:Introduction to ASP.NET Core 关于ASP.NET Core ASP.NET Core 是一个全新的开源.跨平台框架, ...
随机推荐
- 【Linux】查看进程号
1.查看占用8080端口的进程号 lsof -i: | awk '{print $2}' | uniq | grep -P -o "[0-9]{2,5}" 2.查看使用java进程 ...
- centos开放端口8080
今天购买了云服务器,玩耍一下,配置好了jdk和tomcat后,发现访问不了8080端口,telnet 不通,由此想到了防火墙挡住了. 配置规则: iptables -I INPUT -p tcp -- ...
- php ddos 安全处理代码
<?php//查询禁止IP$ip =$_SERVER['REMOTE_ADDR'];$fileht=".htaccess2";if(!file_exists($fileht) ...
- windows下命令行模式中cd命令无效的原因
当我们执行cmd 想切换当前工作目录时,会发现windows下命令行模式中cd命令没有生效,到底是什么原因呢? 例如: 当我们想切换到 D:\MySql\mysql-5.7.19-winx64\bin ...
- wcf 上传文件报413,404和发布错误
上传文件错误: 其实要修改所有的服务,不管是服务端还是客户端,Binding那边增加一个没有设置名字的默认配置就OK了: <binding closeTimeout="00:10 ...
- 利用wireshark任意获取qq好友IP实施精准定位
没事玩一把,感觉还挺有趣,首先打开wireshark: 不管你连接的什么网,如图我连接的是WLAN,双击进入如图界面: ctrl-f进行搜索:如图 选择分组详情,字符串,并输入020048.这时候你就 ...
- github+hexo搭建自己的博客网站(七)注意事项(避免read.me,CNAME文件的覆盖,手动改github page的域名)
详细的可以查看hexo博客的演示:https://saucxs.github.io/ 绑定域名可以查看:http://www.chengxinsong.cn 可以查看在github上生成的静态文件(如 ...
- java程序的内存分配
java程序的内存分配 JAVA 文件编译执行与虚拟机(JVM)介绍 Java 虚拟机(JVM)是可运行Java代码的假想计算机.只要根据JVM规格描述将解释器移植到特定的计算机上,就能保证经过编译的 ...
- C# 模拟网站登陆并截图
1.在窗体上加一个按钮,为按钮添加点击事件 private void button1_Click(object sender, EventArgs e) { Bitmap m_Bitmap = Web ...
- NHibernate教程(21)——二级缓存(下)
本节内容 引入 使用NHibernate二级缓存 启用缓存查询 管理NHibernate二级缓存 结语 引入 这篇我还继续上一篇的话题聊聊NHibernate二级缓存剩下的内容,比如你修改.删除数据时 ...