WebSocket服务器(物联网下行通知神器)
HttpServer是一個輕量級Web服務器,用于在嵌入式設備以及客戶端環(huán)境中提供簡單Web服務,同時也支持標準WebSocket服務。
本文例程基于vs2022,基礎例程可參考:https://www.yuque.com/smartstone/nx/httpserver
WebSocket服務端
WebSocket服務端功能由HttpServer提供,只是映射到WebSocket特有的處理器上。
vs2022新建.NET6.0控制臺項目,Nuget引用 NewLife.Core,使用以下例程:
using NewLife.Http; using NewLife.Log; using System;XTrace.UseConsole();var server = new HttpServer {Port = 8080,Log = XTrace.Log,SessionLog = XTrace.Log }; server.Map("/ws", new MyWebSocket()); server.Start();Console.ReadLine();class MyWebSocket : IHttpHandler {/// <summary>處理請求</summary>/// <param name="context"></param>public virtual void ProcessRequest(IHttpContext context){var ws = context.WebSocket;ws.Handler = ProcessMessage;var source = new CancellationTokenSource();Task.Run(() => consumeMessage(ws, "nodeCode", source));WriteLog("WebSocket連接 {0}", context.Connection.Remote);}/// <summary>處理消息</summary>/// <param name="socket"></param>/// <param name="message"></param>public virtual void ProcessMessage(WebSocket socket, WebSocketMessage message){var remote = socket.Context.Connection.Remote;var msg = message.Payload?.ToStr();switch (message.Type){case WebSocketMessageType.Text:WriteLog("WebSocket收到[{0}] {1}", message.Type, msg);// 群發(fā)所有客戶端socket.SendAll($"[{remote}]說,{msg}");break;case WebSocketMessageType.Close:WriteLog("WebSocket關(guān)閉[{0}] [{1}] {2}", remote, message.CloseStatus, message.StatusDescription);break;case WebSocketMessageType.Ping:case WebSocketMessageType.Pong:WriteLog("WebSocket心跳[{0}] {1}", message.Type, msg);break;default:WriteLog("WebSocket收到[{0}] {1}", message.Type, msg);break;}}private void WriteLog(String format, params Object[] args) => XTrace.WriteLine(format, args); }映射路由/ws到一個自定義處理器MyWebSocket上,該處理器包括了 ProcessRequest 和 ProcessMessage 。
ProcessRequest。收到WebSocket請求時觸發(fā)一次,此時可驗證訪問者是否合法,例如借助JWT等Token技術(shù)。Handler屬性設置為ProcessMessage,用于處理后續(xù)WebSocket消息。
ProcessMessage。建立WebSocket握手后,每次收到WebSocket消息(數(shù)據(jù)幀),都將調(diào)用該方法,包括二進制、文本、心跳和斷開等多種消息類型。
Send。發(fā)送消息給客戶端。
SendAll。群發(fā)消息給所有客戶端。
Close。關(guān)閉連接。
跑起來:
可以看到,仍然是普通HttpServer監(jiān)聽8080端口。保持打開,不要關(guān)閉,下面客戶端測試需要用到
WebClient客戶端
借助.NET自身的ClientWebSocket,可以輕松構(gòu)建WebSocket通信。
vs2022新建.NET6.0控制臺項目,Nuget引用 NewLife.Core,使用以下例程:
using NewLife; using NewLife.Data; using NewLife.Log; using System; using System.Net.WebSockets;XTrace.UseConsole();var client = new ClientWebSocket(); await client.ConnectAsync(new Uri("ws://127.0.0.1:8080/ws"), default); await client.SendAsync("Hello NewLife".GetBytes(), WebSocketMessageType.Text, true, default);var buf = new Byte[1024]; var rs = await client.ReceiveAsync(buf, default); XTrace.WriteLine(new Packet(buf, 0, rs.Count).ToStr());await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "通信完成", default); XTrace.WriteLine("Close [{0}] {1}", client.CloseStatus, client.CloseStatusDescription);Console.ReadLine();建立到服務端的連接后,向服務端發(fā)送字符串“Hello NewLife”,然后使用1024緩沖區(qū)接收一次響應數(shù)據(jù),接著友好斷開連接。
跑起來:
查看服務端:
可以看到,服務端ProcessRequest收到了客戶端的WebSocket連接請求。兩次ProcessMessage,第一次收到Text數(shù)據(jù)幀,也就是文本“Hello NewLife”,第二次是Close數(shù)據(jù)幀。
客戶端也收到了服務端SendAll群發(fā)的數(shù)據(jù),感興趣的同學可以多開幾個客戶端試試。
物聯(lián)網(wǎng)平臺中使用
在物聯(lián)網(wǎng)平臺中,設備與服務端建立WebSocket長連接后,可以實時下發(fā)通知。
我們使用消息隊列架構(gòu),如果隊列中有消息,則通過WebSocket推給設備端。
消息大循環(huán)結(jié)合WebSocket如下:
private async Task consumeMessage(WebSocket socket, String node, CancellationTokenSource source){var cancellationToken = source.Token;var queue = QueueHost.GetQueue<String>($"cmd:{node}");try{while (!cancellationToken.IsCancellationRequested){var msg = await queue.TakeOneAsync(10_000);if (msg != null){XTrace.WriteLine("WebSocket發(fā)送 {0} {1}", node, msg);socket.Send(msg.GetBytes(), WebSocketMessageType.Text);}else{await Task.Delay(1_000, cancellationToken);}}}catch (Exception ex){XTrace.WriteException(ex);}finally{source.Cancel();}}再修改 ProcessRequest ,握手后異步啟動大循環(huán):
/// <summary>處理請求</summary>/// <param name="context"></param>public virtual void ProcessRequest(IHttpContext context){var ws = context.WebSocket;ws.Handler = ProcessMessage;var source = new CancellationTokenSource();Task.Run(() => consumeMessage(ws, "nodeCode", source));WriteLog("WebSocket連接 {0}", context.Connection.Remote);}借助Redis消息隊列,每個設備一個Topic,對應一個WebSocket連接和消費大循環(huán)。
注:以上代碼來自星塵 StarServer。
總結(jié)
以上是生活随笔為你收集整理的WebSocket服务器(物联网下行通知神器)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Blazor+Dapr+K8s微服务之开
- 下一篇: WeihanLi.Npoi 1.20.0