NetCore WebSocket 即時通訊示例

来源:http://www.cnblogs.com/besuccess/archive/2017/06/18/7043885.html
-Advertisement-
Play Games

1.新建Netcore Web項目 2.創建簡易通訊協議 SenderID發送者ID ReceiverID 接受者ID MessageType 消息類型 Text Voice 等等 Content 消息內容 3.添加中間件ChatWebSocketMiddleware 4.在Startup.cs中使 ...


1.新建Netcore Web項目

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.創建簡易通訊協議

 

public class MsgTemplate
    {
        public string SenderID { get; set; }
        public string ReceiverID { get; set; }
        public string MessageType { get; set; }
        public string Content { get; set; }
    }

SenderID發送者ID

ReceiverID 接受者ID

MessageType 消息類型  Text  Voice 等等

Content 消息內容 

3.添加中間件ChatWebSocketMiddleware

 

  1 public class ChatWebSocketMiddleware
  2     {
  3         private static ConcurrentDictionary<string, System.Net.WebSockets.WebSocket> _sockets = new ConcurrentDictionary<string, System.Net.WebSockets.WebSocket>();
  4 
  5         private readonly RequestDelegate _next;
  6 
  7         public ChatWebSocketMiddleware(RequestDelegate next)
  8         {
  9             _next = next;
 10         }
 11 
 12         public async Task Invoke(HttpContext context)
 13         {
 14             if (!context.WebSockets.IsWebSocketRequest)
 15             {
 16                 await _next.Invoke(context);
 17                 return;
 18             }
 19             System.Net.WebSockets.WebSocket dummy;
 20 
 21             CancellationToken ct = context.RequestAborted;
 22             var currentSocket = await context.WebSockets.AcceptWebSocketAsync();
 23             //string socketId = Guid.NewGuid().ToString();
 24             string socketId = context.Request.Query["sid"].ToString();
 25             if (!_sockets.ContainsKey(socketId))
 26             {
 27                 _sockets.TryAdd(socketId, currentSocket);
 28             }
 29             //_sockets.TryRemove(socketId, out dummy);
 30             //_sockets.TryAdd(socketId, currentSocket);
 31 
 32             while (true)
 33             {
 34                 if (ct.IsCancellationRequested)
 35                 {
 36                     break;
 37                 }
 38 
 39                 string response = await ReceiveStringAsync(currentSocket, ct);
 40                 MsgTemplate msg = JsonConvert.DeserializeObject<MsgTemplate>(response);
 41 
 42                 if (string.IsNullOrEmpty(response))
 43                 {
 44                     if (currentSocket.State != WebSocketState.Open)
 45                     {
 46                         break;
 47                     }
 48 
 49                     continue;
 50                 }
 51 
 52                 foreach (var socket in _sockets)
 53                 {
 54                     if (socket.Value.State != WebSocketState.Open)
 55                     {
 56                         continue;
 57                     }
 58                     if (socket.Key == msg.ReceiverID || socket.Key == socketId)
 59                     {
 60                         await SendStringAsync(socket.Value, JsonConvert.SerializeObject(msg), ct);
 61                     }
 62                 }
 63             }
 64 
 65             //_sockets.TryRemove(socketId, out dummy);
 66 
 67             await currentSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", ct);
 68             currentSocket.Dispose();
 69         }
 70 
 71         private static Task SendStringAsync(System.Net.WebSockets.WebSocket socket, string data, CancellationToken ct = default(CancellationToken))
 72         {
 73             var buffer = Encoding.UTF8.GetBytes(data);
 74             var segment = new ArraySegment<byte>(buffer);
 75             return socket.SendAsync(segment, WebSocketMessageType.Text, true, ct);
 76         }
 77 
 78         private static async Task<string> ReceiveStringAsync(System.Net.WebSockets.WebSocket socket, CancellationToken ct = default(CancellationToken))
 79         {
 80             var buffer = new ArraySegment<byte>(new byte[8192]);
 81             using (var ms = new MemoryStream())
 82             {
 83                 WebSocketReceiveResult result;
 84                 do
 85                 {
 86                     ct.ThrowIfCancellationRequested();
 87 
 88                     result = await socket.ReceiveAsync(buffer, ct);
 89                     ms.Write(buffer.Array, buffer.Offset, result.Count);
 90                 }
 91                 while (!result.EndOfMessage);
 92 
 93                 ms.Seek(0, SeekOrigin.Begin);
 94                 if (result.MessageType != WebSocketMessageType.Text)
 95                 {
 96                     return null;
 97                 }
 98 
 99                 using (var reader = new StreamReader(ms, Encoding.UTF8))
100                 {
101                     return await reader.ReadToEndAsync();
102                 }
103             }
104         }
105     }

 

控制只有接收者才能收到消息
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.建立移動端測試示例 這裡採用Ionic3運行在web端

   創建ionic3項目略過 新手可點這裡查看  或者有Angular2/4項目竟然可直接往下看 

   (1) 啟動Ionic項目

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

當初創建ionic3項目時候遇到不少問題

比如ionic-cli初始化項目失敗 切換到預設npmorg源就好了

比如ionic serve失敗 打開代理允許FQ就好了

啟動後界面是這樣式的

 

(2) 創建聊天視窗dialog  具體佈局實現 模塊載入略過 直接進入websocket實現

      在這之前別忘了啟動web項目 否則會出現這樣情況 鏈接不到服務

(3)dialog.ts具體實現

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為我要發送的內容 比如"hello world"
        var msgObj = {
            SenderID: "222",
            ReceiverID: "111",
            MessageType: "text",
            Content: msg
        };
        this.ws.send(JSON.stringify(msgObj));
    }
ws://localhost:56892?sid=222 這是websocke服務鏈接地址 sid表示著我這個端的WebSocke唯一標識  找到這個key就可以找到我這個用戶端了   6.在web端也實現一個會話視窗
<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 + "//" + 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>

 

基本開發完成 接下來看看效果

 

7.web和webapp端對話

 

 8.webapp發送  web接收

9.目前就實現了這麼多  因為項目還涉及其它技術 暫時不開放源碼了 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 軟體環境: Win7 x64 SP1 SQL Server 2008r2 Visual Studio 2017 Professional 目標:取出示例資料庫 ReportServer 的表 Roles 中的所有記錄並顯示。 步驟: 一、添加軟體包 使用NuGet添加以下軟體包: ServiceSt ...
  • 一、泛型 假設我要寫個公用的輸出傳入參數的方法(不用泛型),因為萬物皆對象的理由,我先定義一個方法show(object obj),如下麵所示: 執行這個方法 如果傳入的是值類型,值類型轉換為引用類型,我們知道會發生裝箱,這是對性能的損害,想想如果是個集合,就得多次執行裝箱、拆箱操作。如ArrayL ...
  • .net core 填坑記之二目錄問題(獲取當前目錄、創建目錄) ...
  • SqlSugar 4.0 ORM框架的優勢 為了未來能夠更好的支持多庫分散式的存儲,並行計算等功能,將SqlSugar3.x全部重寫,現有的架構可以輕鬆擴展多庫。 源碼下載: https://github.com/sunkaixuan/SqlSugar 1.性能 性能最好的ORM之一,具有超越Dap ...
  • 上一篇中講到XML基本的結構,還有增刪改查的方法,這一篇中我們就來利用XML來完成一個簡單的訂單系統,主要是實現一個簡單學生名單的增刪改查,如果想要應用到實際的環境中建議考慮數據量的問題,如果數據量大使用XML的話會比較耗時,使用SQL的性能會好一些 這裡使用WinForm窗體程式,大致界面如下: ...
  • 在講了一系列的基礎文檔之後,現在開始講一些實例。對於一些數據不是很大的程式,或者只是一些配置文件,需要本地存儲的,完全可以使用XML代替資料庫,因為只是去操作單個文件會比操作資料庫要簡單很多,在程式中訪問和操作XML一般使用DOM(文檔對象模型)和流模式。DOM運行編輯和更新XML文檔,可以隨機訪問 ...
  • 之前兩篇文檔講述了C#中的面向對象的概念,其實這個概念對於很多種語言都是通用的,只不過每種語言具體實現的過程方法不一樣,比如Java、C++、python等,這些都是很流行的面向對象的語言在編程語言排行榜中都是屬於前幾名的。面向對象中比較難以理解的就是多態的概念,多態我將留到後面的章節去講,現在繼續 ...
  • 1、安裝ElasticSearch https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html 這個頁面有詳細安裝步驟 2、安裝Head插件 head插件可以管理elasticsearch集群,管理 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...