NetCore WebSocket即時(shí)通訊示例
NetCore WebSocket 即時(shí)通訊示例,供大家參考,具體內(nèi)容如下
1.新建Netcore Web項(xiàng)目
2.創(chuàng)建簡(jiǎn)易通訊協(xié)議
public class MsgTemplate { public string SenderID { get; set; } public string ReceiverID { get; set; } public string MessageType { get; set; } public string Content { get; set; } }
SenderID發(fā)送者ID
ReceiverID 接受者ID
MessageType 消息類型 Text Voice 等等
Content 消息內(nèi)容
3.添加中間件ChatWebSocketMiddleware
public class ChatWebSocketMiddleware { private static ConcurrentDictionary<string, System.Net.WebSockets.WebSocket> _sockets = new ConcurrentDictionary<string, System.Net.WebSockets.WebSocket>(); private readonly RequestDelegate _next; public ChatWebSocketMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { if (!context.WebSockets.IsWebSocketRequest) { await _next.Invoke(context); return; } System.Net.WebSockets.WebSocket dummy; CancellationToken ct = context.RequestAborted; var currentSocket = await context.WebSockets.AcceptWebSocketAsync(); //string socketId = Guid.NewGuid().ToString(); string socketId = context.Request.Query["sid"].ToString(); if (!_sockets.ContainsKey(socketId)) { _sockets.TryAdd(socketId, currentSocket); } //_sockets.TryRemove(socketId, out dummy); //_sockets.TryAdd(socketId, currentSocket); while (true) { if (ct.IsCancellationRequested) { break; } string response = await ReceiveStringAsync(currentSocket, ct); MsgTemplate msg = JsonConvert.DeserializeObject<MsgTemplate>(response); if (string.IsNullOrEmpty(response)) { if (currentSocket.State != WebSocketState.Open) { break; } continue; } foreach (var socket in _sockets) { if (socket.Value.State != WebSocketState.Open) { continue; } if (socket.Key == msg.ReceiverID || socket.Key == socketId) { await SendStringAsync(socket.Value, JsonConvert.SerializeObject(msg), ct); } } } //_sockets.TryRemove(socketId, out dummy); await currentSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", ct); currentSocket.Dispose(); } private static Task SendStringAsync(System.Net.WebSockets.WebSocket socket, string data, CancellationToken ct = default(CancellationToken)) { var buffer = Encoding.UTF8.GetBytes(data); var segment = new ArraySegment<byte>(buffer); return socket.SendAsync(segment, WebSocketMessageType.Text, true, ct); } private static async Task<string> ReceiveStringAsync(System.Net.WebSockets.WebSocket socket, CancellationToken ct = default(CancellationToken)) { var buffer = new ArraySegment<byte>(new byte[8192]); using (var ms = new MemoryStream()) { WebSocketReceiveResult result; do { ct.ThrowIfCancellationRequested(); result = await socket.ReceiveAsync(buffer, ct); 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(); } } } }
控制只有接收者才能收到消息
if (socket.Key == msg.ReceiverID || socket.Key == socketId) { await SendStringAsync(socket.Value,JsonConvert.SerializeObject(msg), ct); }
4.在Startup.cs中使用中間件
app.UseWebSockets(); app.UseMiddleware<ChatWebSocketMiddleware>();
5.建立移動(dòng)端測(cè)試示例 這里采用Ionic3運(yùn)行在web端
創(chuàng)建ionic3項(xiàng)目略過(guò) 新手可點(diǎn)這里查看 或者有Angular2/4項(xiàng)目竟然可直接往下看
(1) 啟動(dòng)Ionic項(xiàng)目
當(dāng)初創(chuàng)建ionic3項(xiàng)目時(shí)候遇到不少問(wèn)題
比如ionic-cli初始化項(xiàng)目失敗 切換到默認(rèn)npmorg源就好了
比如ionic serve失敗 打開(kāi)代理允許FQ就好了
啟動(dòng)后界面是這樣式的
(2) 創(chuàng)建聊天窗口dialog 具體布局實(shí)現(xiàn) 模塊加載略過(guò)直接進(jìn)入websocket實(shí)現(xiàn)
在這之前別忘了啟動(dòng)web項(xiàng)目 否則會(huì)出現(xiàn)這樣情況 鏈接不到服務(wù)
(3)dialog.ts具體實(shí)現(xiàn)
export class Dialog { private ws: any; private msgArr: Array<any>; constructor(private httpService: HttpService) { this.msgArr = []; } ionViewDidEnter() { if (!this.ws) { this.ws = new WebSocket("ws://localhost:56892?sid=222"); this.ws.onopen = () => { console.log('open'); }; this.ws.onmessage = (event) => { console.log('new message: ' + event.data); var msgObj = JSON.parse(event.data); this.msgArr.push(msgObj);; }; this.ws.onerror = () => { console.log('error occurred!'); }; this.ws.onclose = (event) => { console.log('close code=' + event.code); }; } } sendMsg(msg) {//msg為我要發(fā)送的內(nèi)容 比如"hello world" var msgObj = { SenderID: "222", ReceiverID: "111", MessageType: "text", Content: msg }; this.ws.send(JSON.stringify(msgObj)); }
ws://localhost:56892?sid=222 這是websocke服務(wù)鏈接地址
sid表示著我這個(gè)端的WebSocke唯一標(biāo)識(shí) 找到這個(gè)key就可以找到我這個(gè)用戶端了
6.在web端也實(shí)現(xiàn)一個(gè)會(huì)話窗口
<div class="container" style="width:90%;margin:0px auto;border:1px solid steelblue;"> <div class="msg"> <div id="msgs" style="height:200px;"></div> </div> <div style="display:block;width:100%"> <input type="text" style="max-width:unset;width:100%;max-width:100%" id="MessageField" placeholder="type message and press enter" /> </div> </div>
<script> $(function () { $('.navbar-default').addClass('on'); var userName = '@Model'; var protocol = location.protocol === "https:" ? "wss:" : "ws:"; var wsUri = protocol + "http://" + window.location.host + "?sid=111"; var socket = new WebSocket(wsUri); socket.onopen = e => { console.log("socket opened", e); }; socket.onclose = function (e) { console.log("socket closed", e); }; socket.onmessage = function (e) { console.log(e); var msgObj = JSON.parse(e.data); $('#msgs').append(msgObj.Content + '<br />'); }; socket.onerror = function (e) { console.error(e.data); }; $('#MessageField').keypress(function (e) { if (e.which != 13) { return; } e.preventDefault(); var message = $('#MessageField').val(); var msgObj = { SenderID:"111", ReceiverID:"222", MessageType: "text", Content: message }; socket.send(JSON.stringify(msgObj)); $('#MessageField').val(''); }); }); </script>
基本開(kāi)發(fā)完成 接下來(lái)看看效果
7.web和webapp端對(duì)話
8.webapp發(fā)送 web接收
9.目前就實(shí)現(xiàn)了這么多 因?yàn)轫?xiàng)目還涉及其它技術(shù) 暫時(shí)不開(kāi)放源碼了
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
asp.net sqlconnection con.close和con.dispose區(qū)別
con.close是用來(lái)關(guān)閉和數(shù)據(jù)庫(kù)的連接,相對(duì)于open2008-12-12LINQ字符串向datetime 轉(zhuǎn)換時(shí)失敗的處理方法
LINQ字符串向datetime 轉(zhuǎn)換時(shí)失敗的處理方法,需要的朋友可以可以參考一下2013-03-03asp.net 禁用viewstate在web.config里
在web.config里設(shè)置禁用viewstate的代碼。2009-06-06.NET驗(yàn)證組件Fluent Validation使用指南
本文介紹了.NET驗(yàn)證組件Fluent Validation,并通過(guò)實(shí)例告訴我們這個(gè)驗(yàn)證組件的使用方法,以及與asp.net mvc驗(yàn)證庫(kù)的整合方案,這里推薦給有相同需求的小伙伴2014-11-11.net?core?api接口JWT方式認(rèn)證Token
本文詳細(xì)講解了.net?core?api接口JWT方式認(rèn)證Token,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12ASP.NET實(shí)現(xiàn)級(jí)聯(lián)下拉框效果實(shí)例講解
這篇文章主要為大家詳細(xì)介紹了ASP.NET實(shí)現(xiàn)級(jí)聯(lián)下拉框效果實(shí)例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-09-09.NET開(kāi)發(fā)實(shí)現(xiàn)一個(gè)微信跳一跳的輔助程序
最近比較火的小游戲就是微信跳一跳了,下面這篇文章主要給大家介紹了關(guān)于如何利用.NET開(kāi)發(fā)實(shí)現(xiàn)一個(gè)微信跳一跳輔助程序的相關(guān)資料,利用此輔助可以輕松的實(shí)現(xiàn)高分,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01asp.net中調(diào)用Office來(lái)制作3D統(tǒng)計(jì)圖的實(shí)例代碼
這篇文章介紹了asp.net中調(diào)用Office來(lái)制作3D統(tǒng)計(jì)圖的實(shí)例代碼,有需要的朋友可以參考一下2013-11-11