C# WebSocket的簡單使用【使用Fleck實現】

【君莫笑】發表於2024-11-06

有bug,不推薦使用

有bug,不推薦使用

有bug,不推薦使用

2.WebSocketHelper

新建 WebSocketHelper.cs

using Fleck;
 
namespace WebSocket
{
    internal class WebSocketHelper
    {
        //客戶端url以及其對應的Socket物件字典
        IDictionary<string, IWebSocketConnection> dic_Sockets = new Dictionary<string, IWebSocketConnection>();
        //建立一個 websocket ,0.0.0.0 為監聽所有的的地址
        WebSocketServer server = new WebSocketServer("ws://0.0.0.0:30000");
 
        //開啟連線委託
        public delegate void _OnOpen(string ip);
        public event _OnOpen OnOpen;
        //關閉連線委託
        public delegate void _OnClose(string ip);
        public event _OnClose OnClose;
        //當收到訊息
        public delegate void _OnMessage(string ip, string msg);
        public event _OnMessage OnMessage;
 
        /// <summary>
        /// 初始化
        /// </summary>
        private void Init()
        {
            //出錯後進行重啟
            server.RestartAfterListenError = true;
 
            //開始監聽
            server.Start(socket =>
            {
                //連線建立事件
                socket.OnOpen = () =>
                {
                    //獲取客戶端網頁的url
                    string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
                    dic_Sockets.Add(clientUrl, socket);
                    if (OnOpen != null) OnOpen(clientUrl);
                    Console.WriteLine(DateTime.Now.ToString() + " | 伺服器:和客戶端:" + clientUrl + " 建立WebSock連線!");
                };
 
                //連線關閉事件
                socket.OnClose = () =>
                {
                    string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
                    //如果存在這個客戶端,那麼對這個socket進行移除
                    if (dic_Sockets.ContainsKey(clientUrl))
                    {
                        dic_Sockets.Remove(clientUrl);
                        if (OnClose != null) OnClose(clientUrl);
                    }
                    Console.WriteLine(DateTime.Now.ToString() + " | 伺服器:和客戶端:" + clientUrl + " 斷開WebSock連線!");
                };
 
                //接受客戶端網頁訊息事件
                socket.OnMessage = message =>
                {
                    string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
                    Receive(clientUrl, message);
                    if (OnMessage != null) 
                        OnMessage(clientUrl, message);
                };
            });
        }
 
        /// <summary>
        /// 向客戶端傳送訊息
        /// </summary>
        /// <param name="webSocketConnection">客戶端例項</param>
        /// <param name="message">訊息內容</param>
        public void Send(string clientUrl, string message)
        {
            IWebSocketConnection webSocketConnection = GetUserSocketInstance(clientUrl);
            if (webSocketConnection != null)
            {
                if (webSocketConnection.IsAvailable)
                {
                    webSocketConnection.Send(message);
                }
            }
        }
 
        /// <summary>
        /// 接收訊息
        /// </summary>
        /// <param name="clientUrl"></param>
        /// <param name="message"></param>
        private void Receive(string clientUrl, string message)
        {
            Console.WriteLine(DateTime.Now.ToString() + " | 伺服器:【收到】來客戶端:" + clientUrl + "的資訊:\n" + message);
        }
 
        /// <summary>
        /// 獲取使用者例項
        /// </summary>
        /// <param name="clientUrl">使用者的地址</param>
        public IWebSocketConnection GetUserSocketInstance(string clientUrl)
        {
            if (dic_Sockets.ContainsKey(clientUrl))
                return dic_Sockets[clientUrl];
            else
                return null;
        }
 
        /// <summary>
        /// 關閉某一個使用者的連線
        /// </summary>
        /// <param name="clientUrl"></param>
        public void CloseUserConnect(string clientUrl)
        {
            IWebSocketConnection webSocketConnection = GetUserSocketInstance(clientUrl);
            if (webSocketConnection != null)
                webSocketConnection.Close();
        }
 
        /// <summary>
        /// 關閉與客戶端的所有的連線
        /// </summary>
        public void CloseAllConnect()
        {
            foreach (var item in dic_Sockets.Values)
            {
                if (item != null)
                {
                    item.Close();
                }
            }
        }
 
        public WebSocketHelper()
        {
            Init();
        }
    }
}

3.Program

目前並沒有寫入太多功能,只是加了控制檯輸入文字,然後轉發給所有連線的使用者

using WebSocket;
 
namespace WebSocketNet6
{
    internal class Program
    {
        private static List<string> IPList = new List<string>();
        private static WebSocketHelper WebSocketHelpers = new WebSocketHelper();
 
        static void Main(string[] args)
        {
            WebSocketHelpers.OnOpen += WebSocketHelper_OnOpen;
            WebSocketHelpers.OnClose += WebSocketHelper_OnClose;
            WebSocketHelpers.OnMessage += WebSocketHelper_OnMessage;
 
            while (true)
            {
                //監聽控制檯的輸入
                string? contetn = Console.ReadLine();
                if (contetn != null)
                {
                    Relay(contetn);
 
                    if (contetn.Equals("q"))
                    {
                        WebSocketHelpers.CloseAllConnect();
                        Console.WriteLine("關閉所有客戶端的連線");
                        break;
                    }
                }
                Thread.Sleep(10);
            }
        }
 
        #region WebSocket回撥
 
        //當收到訊息
        private static void WebSocketHelper_OnMessage(string ip, string msg)
        {
            for (int i = 0; i < IPList.Count; i++)
            {
                if (IPList[i] != ip)
                {
                    WebSocketHelpers.Send(IPList[i], msg);
                }
            }
        }
 
        //當客戶端斷開連線
        private static void WebSocketHelper_OnClose(string ip)
        {
            if (IPList.Contains(ip))
            {
                IPList.Remove(ip);
            }
        }
 
        //當客戶端連線上伺服器
        private static void WebSocketHelper_OnOpen(string ip)
        {
            if (!IPList.Contains(ip))
            {
                IPList.Add(ip);
            }
        }
 
        #endregion
 
        //轉發所有客戶端
        private static void Relay(string content)
        {
            if (IPList.Count == 0)  return;
 
            for (int i = 0; i < IPList.Count; i++)
            {
                WebSocketHelpers.Send(IPList[i], content);
            }
        }
    }
}

三、客戶端

1.html

 
<!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 += "連線伺服器..<br/>";
 
            // 建立一個新的websocket並連線
            window.ws = new wsImpl('ws://localhost:30000/');
 
            // 當資料來自伺服器時,將呼叫此方法
            ws.onmessage = function (evt) {
                inc.innerHTML += ("[來自伺服器的訊息] " + evt.data + '<br/>');
                console.log("[來自伺服器的訊息] " + evt.data);
            };
 
            // 當建立連線時,將呼叫此方法
            ws.onopen = function () {
                inc.innerHTML += '已建立連線.. <br/>';
            };
 
            // 當連線關閉時,將呼叫此方法
            ws.onclose = function () {
                inc.innerHTML += '連線已關閉.. <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">
        <span>輸入內容按回車傳送訊息</span> <br/>
        <input id="sendText" placeholder="Text to send" />
    </form>
    <pre id="incomming"></pre>
</body>
</html>

2.Winform

新建一個 winform 專案

先安裝外掛 SuperSocket.ClientEngine

using SuperSocket.ClientEngine;
using System;
using System.Threading;
using System.Threading.Tasks;
using WebSocket4Net;
 
namespace WebSocketClient
{
    public class WSocketClient : IDisposable
    {
        //收到訊息後的回撥
        //public event Action<string> MessageReceived;
        public Action<string> MessageReceived;
 
        private WebSocket4Net.WebSocket _webSocket;
 
        /// <summary>
        /// 檢查重連執行緒
        /// </summary>
        Thread _thread;
        bool _isRunning = false;
 
        /// <summary>
        /// 是否在執行中
        /// </summary>
        public bool IsRunning => _isRunning;
 
        /// <summary>
        /// WebSocket連線地址
        /// </summary>
        public string ServerPath { get; set; }
 
        public WSocketClient(string url)
        {
            ServerPath = url;
            this._webSocket = new WebSocket4Net.WebSocket(url);
            this._webSocket.Opened += WebSocket_Opened;
            this._webSocket.Error += WebSocket_Error;
            this._webSocket.Closed += WebSocket_Closed;
            this._webSocket.MessageReceived += WebSocket_MessageReceived;
        }
 
        /// <summary>
        /// 連線方法
        /// <returns></returns>
        public bool Start()
        {
            bool result = true;
            try
            {
                this._webSocket.Open();
                this._isRunning = true;
                this._thread = new Thread(new ThreadStart(CheckConnection));
                this._thread.Start();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                result = false;
                this._isRunning = false;
            }
            return result;
        }
 
        /// <summary>
        /// 訊息收到事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void WebSocket_MessageReceived(object sender, MessageReceivedEventArgs e)
        {
            Console.WriteLine("Received:" + e.Message);
 
            if (MessageReceived != null)
                MessageReceived(e.Message);
        }
 
        /// <summary>
        /// Socket關閉事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void WebSocket_Closed(object sender, EventArgs e)
        {
            Console.WriteLine("websocket_Closed");
        }
 
        /// <summary>
        /// Socket報錯事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void WebSocket_Error(object sender, ErrorEventArgs e)
        {
            Console.WriteLine("websocket_Error:" + e.Exception.ToString());
        }
 
        /// <summary>
        /// Socket開啟事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void WebSocket_Opened(object sender, EventArgs e)
        {
            Console.WriteLine("websocket_Opened");
        }
 
        /// <summary>
        /// 檢查重連執行緒
        /// </summary>
        private void CheckConnection()
        {
            do
            {
                try
                {
                    if (this._webSocket.State != WebSocket4Net.WebSocketState.Open && this._webSocket.State != WebSocket4Net.WebSocketState.Connecting)
                    {
                        Console.WriteLine("Reconnect websocket WebSocketState:" + this._webSocket.State);
 
                        this._webSocket.Close();
                        this._webSocket.Open();
 
                        Console.WriteLine("正在重連");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
                System.Threading.Thread.Sleep(5000);
            } while (this._isRunning);
        }
 
        /// <summary>
        /// 傳送訊息
        /// </summary>
        /// <param name="Message"></param>
        public void SendMessage(string Message)
        {
            Task.Factory.StartNew(() =>
            {
                if (_webSocket != null && _webSocket.State == WebSocket4Net.WebSocketState.Open)
                {
                    this._webSocket.Send(Message);
                }
            });
        }
 
        public void Dispose()
        {
            try
            {
                _thread?.Abort();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            this._webSocket.Close();
            this._webSocket.Dispose();
            this._webSocket = null;
            this._isRunning = false;
        }
    }
}

using System;
using System.Windows.Forms;
using WebSocketClient;
 
namespace WinFormWebsocket
{
    public partial class Form1 : Form
    {
        private static string url = "ws://127.0.0.1:30000";
        private WSocketClient client = new WSocketClient(url);
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            Control.CheckForIllegalCrossThreadCalls = false;
            txtServerIP.Text = url;
            client.MessageReceived = MessageReceived;
            this.Text = "客戶端";
        }
 
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if(client.IsRunning)
                client.Dispose();
        }
 
        /// <summary>
        /// 連線伺服器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnConnect_Click(object sender, EventArgs e)
        {
            try
            {
                if(client.IsRunning)
                {
                    AddOrdinaryLog("已經連線伺服器,不能重複執行");
                    return;
                }
 
                bool result = client.Start();
                AddOrdinaryLog("連線是否成功:" + result);
            }
            catch (Exception ex)
            {
                string err = string.Format("連線失敗:{0}", ex.Message);
                Console.WriteLine(err);
                throw;
            }
        }
 
        /// <summary>
        /// 關閉伺服器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnClose_Click(object sender, EventArgs e)
        {
            if (!client.IsRunning)
            {
                AddOrdinaryLog("伺服器未連線");
                return;
            }
 
            // 記得釋放資源否則會造成堆疊
            client.Dispose();
            AddOrdinaryLog("連線已關閉");
        }
 
        /// <summary>
        /// 傳送訊息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSendMsg_Click(object sender, EventArgs e)
        {
            string inputMsg = txtInputMsg.Text;
            if (string.IsNullOrEmpty(inputMsg))
            {
                MessageBox.Show("輸入框不能為空");
                return;
            }
 
            client.SendMessage(inputMsg);
            AddOrdinaryLog(inputMsg);
            txtInputMsg.Text = string.Empty;
        }
 
        /// <summary>
        /// 服務端返回的訊息
        /// </summary>
        private void MessageReceived(string msg)
        {
            AddOrdinaryLog(msg);
        }
 
        /// <summary>
        /// 新增日誌
        /// </summary>
        /// <param name="content"></param>
        private void AddOrdinaryLog(string content)
        {
            //讀取當前ListBox列表長度
            int len = ListBox_OrdinaryLogList.Items.Count;
            //插入新的一行
            ListBox_OrdinaryLogList.Items.Insert(len, content);
            //列表長度大於30,那麼就刪除第1行的資料
            if (len > 30)
                ListBox_OrdinaryLogList.Items.RemoveAt(0);
            //插入新的資料後,將捲軸移動到最下面
            int visibleItems = ListBox_OrdinaryLogList.ClientSize.Height / ListBox_OrdinaryLogList.ItemHeight;
            ListBox_OrdinaryLogList.TopIndex = Math.Max(ListBox_OrdinaryLogList.Items.Count - visibleItems + 1, 0);
        }
    }
}

來源:https://blog.csdn.net/qq_38693757/article/details/127193349

相關文章