使用 WebSocket 封裝成服務進行前后端通訊


[背景]
需要定時查詢數據顯示到前端,剛開始使用想到的是Ajax長輪詢(這樣子資源消耗太多了),然后百度,谷歌,發現Http 有一種新的請求方式

WebSocket

WebSocket 是什么?

在沒有接觸WebSocket之前,聽說過 Socket ,那么 WebSocketSocket 到底是什么,他們二者關系有是什么?

WebSocket Socket 的關系--> 其實討論這個點的的時候,我想到的 JavaJavascript 的關系,但是寫文章不能靠自認為,於是我搜索了一下二者聯系,發現很多博文都沒有說明二者的關系,而是都在對比二者

長答案

當我們探討兩件事物的區別和聯系時,我們想探討些什么?

對於我來說,大多數情況是想知道兩件事物本身,而並不是想只想了解「區別」本身。那么對這個問題最直接的解決方法應該是去了解Socket和WebSocket的來源和用法

那么它們的區別和聯系就不言自明了。

WebSocket和Socket的區別 作者:TheAlchemist

所以, WebSocketSocket 沒有可比性 -->划重點

介紹 一下 WebSocket && Socket

WebSocket

WebSocket 是為了滿足基於 Web 的日益增長的實時通信需求而產生的(一次請求,終身連接-->這里有點問題,大家明白就好,我主要先說的就是比Ajax定時請求 消耗資源少 _)
在傳統的 Web 中,要實現實時通信,通用的方式是采用 HTTP 協議不斷發送請求(AJAX 定時請求)
但這種方式即浪費帶寬(HTTP HEAD 是比較大的),又消耗服務器 CPU 占用(沒有信息也要接受請求)


Socket

Socket可以有很多意思,和IT較相關的本意大致是指在端到端的一個連接中,這兩個端叫做Socket。
對於IT從業者來說,它往往指的是TCP/IP網絡環境中的兩個連接端,大多數的API提供者(如操作系統,JDK)往往會提供基於這種概念的接口
所以對於開發者來說也往往是在說一種編程概念。同時,操作系統中進程間通信也有Socket的概念,但這個Socket就不是基於網絡傳輸層的協議了

作者:TheAlchemist
鏈接:https://www.jianshu.com/p/59b5594ffbb0/
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。

WebSocket Socket 最大的一點 ,就在於傳輸協議的不同

網上就張很神奇的七層協議圖

圖片來自此博客

七層協議

Socket是傳輸控制層協議 -> 這個靠近中間,不注重數據進行,負責數據傳輸,速度較快,功能較少

WebSocket是應用層協議-> 應用層靠近用戶,然后功能多,所以速度較慢,反向代理,負載均衡,這些都是在這個基礎進行

關於 WebSocketSocket 這里我就先講到這里,

下面是代碼實際操作
本篇代碼思路來自
C#版Websocket實例 作者:雨落憂傷
下面我就獻丑了

后端 NetCore 3.1
前端 Html頁面
環境 Windows10
測試瀏覽器 谷歌
借助工具 nssm ,VS2019

   /// <summary>
    /// Send 發送
    /// </summary>
    public class SocketSend
    {
        private delegate int Weekly(WebSocketServer socket, List<IWebSocketConnection> allSockets,
          string Markmessage,
          int Marknum,
          string ConnectsocketnotificationSection = "已連接",
          string ConnectsocketCloseSection = "連接已關閉",
          string ReturnMesSection = "數據已更新!"

          );
        private static int Marknum = 0;
        private static string Markmessage = "";

        public void Run()
        {
            var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json");
            var configurationRoot = builder.Build();
            var ipaddresSection = configurationRoot.GetSection("ipaddres").Value;
            var sockettypeSection = configurationRoot.GetSection("sockettype").Value;
            var ipportSection = configurationRoot.GetSection("ipport").Value;
            var ConnectsocketnotificationSection = configurationRoot.GetSection("Connectsocketnotification").Value;
            var ConnectsocketCloseSection = configurationRoot.GetSection("ConnectsocketCloseSection").Value;
            var ReturnMesSection = configurationRoot.GetSection("ReturnMes").Value;
            FleckLog.Level = LogLevel.Debug;
            var allSockets = new List<IWebSocketConnection>();
            var server = new WebSocketServer($"{sockettypeSection }://{ipaddresSection}:{ ipportSection}");
            try
            {
                Weekly weekly = new Weekly(SendMes);
                weekly.Invoke(server, allSockets, Markmessage, Marknum, ConnectsocketnotificationSection, ConnectsocketCloseSection, ReturnMesSection);

            }
            catch (Exception ex)
            {

                Console.WriteLine($"錯誤:  { ex.Message}");
            }
            var IsExit = Console.ReadLine();
            if (!string.IsNullOrEmpty(IsExit))
            {
                Console.WriteLine("是否關閉程序(Y/N)");
                while (true)
                {
                    IsExit = Console.ReadLine();
                    if (IsExit != "N")
                    {
                        return;
                    }
                }

            }
        }


        /// <summary>
        /// Seed
        /// </summary>
        /// <param name="webSocket"></param>
        /// <param name="allSockets"></param>
        /// <param name="Markmessage"></param>
        /// <param name="Marknum"></param>
        /// <param name="ConnectsocketnotificationSection"></param>
        /// <param name="ConnectsocketCloseSection"></param>
        /// <param name="ReturnMesSection"></param>
        /// <returns></returns>
        private int SendMes(WebSocketServer webSocket, List<IWebSocketConnection> allSockets,
              string Markmessage,
              int Marknum,
              string ConnectsocketnotificationSection = "",
              string ConnectsocketCloseSection = "",
              string ReturnMesSection = ""
              )
        {
            webSocket.Start(socket =>
            {
                socket.OnOpen = () =>
                {
                    Console.WriteLine(ConnectsocketnotificationSection);
                    allSockets.Add(socket);
                };
                socket.OnClose = () =>
                {
                    Console.WriteLine(ConnectsocketCloseSection);
                    allSockets.Remove(socket);

                };
                socket.OnMessage = message =>
                {
                    Markmessage = message;
                    Console.WriteLine(Markmessage);
                    //message 然后開啟查詢
                    allSockets.ToList().ForEach(s => s.Send($"Echo: {message}"));

                };
            });
            while (true)
            {
                Thread.Sleep(100);
                if (Markmessage == "OK")
                {
                    //對返回值進行分析
                    Marknum = ReceiveMes();
                    //  Console.WriteLine("接收num" + Marknum);
                    if (Marknum == 200)
                    {
                        allSockets.ToList().ForEach(s => s.Send(string.IsNullOrEmpty(ReturnMesSection.ToString()) ? "data Upload!" : ReturnMesSection.ToString()));
                        Console.WriteLine($"收到消息=>{Markmessage} 返回前段消息=>{ReturnMesSection.ToString()}");
                        Markmessage = "";
                    }
                    else
                    {
                        allSockets.ToList().ForEach(s => s.Send(Marknum.ToString()));
                    }
                }
                Console.WriteLine($"監聽前端消息=>  {Markmessage}");
            }
        }


        /// <summary>
        /// 接收消息 返回 200成功, 500 表示失敗
        /// </summary>
        /// <returns></returns>
        private int ReceiveMes()
        {
            try
            {
               
                //數據庫查詢
                //查到修改 則跳出循序
                var num = 0;
                while (true)
                {
                    Thread.Sleep(100); //每0.1秒查詢一次
                    num++;
                    Console.WriteLine($"執行數據庫查詢第{num.ToString()}次");
                    if (num > 12)
                    {

                        break;  //跳出數據庫查詢
                    }
                }
                //表示查詢到了數據,返回
                Console.WriteLine($"查詢數據成功,正在進行返回數據操作");
                return 200;
            }
            catch (Exception ex)
            {
                //記錄Log
                return 500;
            }
        } 

使用nssm把生成的exe創建成服務 Windows服務方式運行控制台程序


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
    <title>websocket client</title>
    <script type="text/javascript">
        var start = function () {
            var inc = document.getElementById('incomming');
            var wsImpl = window.WebSocket || window.MozWebSocket;
            var form = document.getElementById('sendForm');
            var input = document.getElementById('sendText');

            inc.innerHTML += "connecting to server ..<br/>";

            // create a new websocket and connect
            window.ws = new wsImpl('ws://192.168.1.107:50000');

            // when data is comming from the server, this metod is called
            ws.onmessage = function (evt) {
                inc.innerHTML += evt.data + '<br/>';
            };

            // when the connection is established, this method is called
            ws.onopen = function () {
                inc.innerHTML += '.. connection open<br/>';
            };

            // when the connection is closed, this method is called
            ws.onclose = function () {
                inc.innerHTML += '.. connection closed<br/>';
            }

            form.addEventListener('submit', function (e) {
                e.preventDefault();
                var val = input.value;
                ws.send(val);
                input.value = "";
            });

        }
        window.onload = start;
    </script>
</head>
<body>
    <form id="sendForm">
        <input id="sendText" placeholder="Text to send" />
    </form>
    <pre id="incomming"></pre>
</body>
</html>

這就是將控制台注入成服務,不過我在這樣做的時候,有個問題,就是在使用控制台的時候,能打印出了console,但是注入了服務之后,他就不會有黑窗口了
所以,這里你想每一步操作都發送到前端也可以,或者記錄log,但是我這里覺得,還是把每一步操作返回前端,出現錯誤就log記錄,好了,本次文章就寫在了這里(認真寫文章,真的耗時間)
所以覺得幫到你了,或者我引用其他博主的文章,系列您能都能點個贊,沒有他們,也不會有我這篇文章 _
有些問題,我可能沒有考慮到,有好的優化方案也請能提出,並附上您的Code

Demo地址
Github: https://github.com/whatarey/WebSocket/tree/master
碼雲: https://gitee.com/Whatarey/WebSocket

文章首發地址 博客園,如果覺得排版不好就點擊原文看吧


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM