C# WebSocketSharp 框架的用法

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

一、概述
WebSocketSharp 是一個 C# 實現 websocket 協議客戶端和服務端,WebSocketSharp 支援RFC 6455;WebSocket客戶端和伺服器;訊息壓縮擴充套件;安全連線;HTTP身份驗證;查詢字串,起始標題和Cookie;透過HTTP代理伺服器連線;.NET Framework 3.5或更高版本(包括相容環境,如Mono)。

github 地址

https://github.com/sta/websocket-sharp

二、伺服器端

伺服器端的程式碼量很少,這裡我全部使用 winform 來展示。

新建一個 winform 專案,介面如下

新建一個類 ServerManager

using System;
using WebSocketSharp.Server;
 
internal class ServerManager
{
    private static WebSocketServer WebSocketServers = null;
 
    public static bool IsListening
    {
        get
        {
            if (WebSocketServers == null)
                return false;
            return WebSocketServers.IsListening;
        }
    }
 
    private static void Init()
    {
        WebSocketServers = new WebSocketServer(8888);
 
        //新增具有指定行為和路徑的WebSocket服務
        //string 引數 表示要新增的服務的絕對路徑
        WebSocketServers.AddWebSocketService<Laputa>("/Laputa");
    }
 
    public static void Open()
    {
        WebSocketServers.Start();
        Console.WriteLine("開啟伺服器");
    }
 
    public static void Close()
    {
        WebSocketServers.Stop();
        Console.WriteLine("關閉伺服器");
    }
 
    static ServerManager()
    {
        Init();
    }
 
    private ServerManager() { }
}

新建一個類 Laputa,這個類相當於在 websocket 裡面負責單獨的模組,同樣的,在客戶端的訪問連結也要配套。

using System;
using WebSocketSharp;
using WebSocketSharp.Server;
 
public class Laputa : WebSocketBehavior
{
    protected override void OnMessage(MessageEventArgs e)
    {
        Console.WriteLine("[OnMessage]" + e.Data);
 
        var msg = e.Data == "BALUS"
                  ? "Are you kidding?"
                  : "I'm not available now.";
        Send(msg);
    }
 
    protected override void OnOpen()
    {
        Console.WriteLine("[OnOpen]");
    }
 
    protected override void OnClose(CloseEventArgs e)
    {
        Console.WriteLine("[OnClose]" + e.Reason);
    }
 
    protected override void OnError(ErrorEventArgs e)
    {
        Console.WriteLine("[OnError]" + e.Message);
    }
}

OnMessage 是指收到客戶端的訊息

OnOpen 客戶端連線到了當前的介面

OnClose 客戶端斷開了連線

OnError websocket 出現了錯誤

接下來就是 winform 介面的程式碼了

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace WebSocketSharpServer
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
 
        }
 
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (ServerManager.IsListening)
                ServerManager.Close();
        }
 
        private void Button_Open_Click(object sender, EventArgs e)
        {
            ServerManager.Open();
        }
 
        private void Button_Close_Click(object sender, EventArgs e)
        {
            ServerManager.Close();
        }
    }
}

伺服器端的程式碼就這麼多,其實還有其他的很多功能,SSL/TLS,Cookies,證書 等,有興趣的可以參考 github 的文件。

using System;
using System.Threading.Tasks;
using WebSocketSharp;
 
/// <summary>
/// Websocket
/// </summary>
internal class NetManager
{
    #region 欄位
 
    private static WebSocket WebSockets = null;
 
    private static int ConsoleCount = 0;
 
    private static System.Windows.Forms.Timer Timer = null;
 
    /// <summary>
    /// 當前的網路是否連線
    /// </summary>
    public static bool IsConnect
    {
        get
        {
            if (WebSockets == null)
                return false;
            return WebSockets.IsAlive;
        }
    }
 
    //這裡ip地址可以從別的地方取值,因為用的 static 靜態建構函式,
    //建構函式會呼叫 Init 方法,這會導致 IPAddress 為 null 就初始化完成了。
    /// <summary>
    /// websocket 的地址,一般以 ws://  或者 wss:// 開頭
    /// </summary>
    public static string IPAddress { get; private set; } = "ws://127.0.0.1:8888/Laputa";
    /// <summary>
    /// 是否顯示ping
    /// </summary>
    public static bool IsShowPingLog { get; set; } = false;
    /// <summary>
    /// 收到伺服器訊息的回撥
    /// </summary>
    public static Action<string> OnMessage = null;
    /// <summary>
    /// 連線成功和斷開連線的回撥
    /// </summary>
    public static Action<bool> OnNetStateChange = null;
 
 
 
    #endregion
 
    #region 初始化
 
    private static void Init()
    {
        if (string.IsNullOrEmpty(IPAddress))
            return;
 
        WebSockets = new WebSocket(IPAddress);
 
        WebSockets.OnOpen += WebSockets_OnOpen;
        WebSockets.OnMessage += WebSockets_OnMessage;
        WebSockets.OnClose += WebSockets_OnClose;
        WebSockets.OnError += WebSockets_OnError;
 
        Console.WriteLine("[NetManager]初始化成功!");
 
        Timer = new System.Windows.Forms.Timer();//例項化Timer類,設定間隔時間(毫秒);
        Timer.Interval = 3000;
        Timer.Tick += Timer_Tick;//到達時間的時候執行事件
    }
 
    private static void Timer_Tick(object sender, EventArgs e)
    {
        if (!WebSockets.IsAlive) return;
 
        WebSockets.Send("ping");
 
        if (IsShowPingLog)
        {
            Console.WriteLine("ping");
 
            ConsoleCount++;
            if (ConsoleCount > 100)
            {
                ConsoleCount = 0;
                Console.Clear();
            }
        }
    }
 
    #endregion
 
    #region WebSocket 相關
 
    private static void WebSockets_OnOpen(object sender, EventArgs e)
    {
        Console.WriteLine("[NetManager][OnOpen] 時間:{0}", DateTime.Now);
        if (OnNetStateChange != null)
            OnNetStateChange(true);
    }
 
    private static void WebSockets_OnError(object sender, ErrorEventArgs e)
    {
        string message = string.Format("[NetManager][OnError]{0}", e.Message);
        Console.WriteLine(message);
    }
 
    private static void WebSockets_OnClose(object sender, CloseEventArgs e)
    {
        Console.WriteLine("[NetManager][OnClose]" + e.Reason);
 
        if (OnNetStateChange != null)
            OnNetStateChange(false);
 
        if (!string.IsNullOrEmpty(e.Reason) && !IsClose)
        {
            DisconnectionReconnects();//斷線重連
        }
    }
 
    private static void WebSockets_OnMessage(object sender, MessageEventArgs e)
    {
        Console.WriteLine("[NetManager][OnMessage]" + e.Data);
 
        //心跳型別訊息
        //if (e.IsPing)
        //{
        //    Console.WriteLine("ping");
        //    return;
        //}
 
        //字串型別的訊息
        if (e.IsText)
        {
            if (OnMessage != null) 
                OnMessage(e.Data);
            return;
        }
 
        //二進位制訊息
        if(e.IsBinary)
        {
            //二進位制使用RawData
            Console.WriteLine(e.RawData);
            return;
        }
    }
 
    #endregion
 
    #region 伺服器開關
 
    private static bool IsClose = false;
 
    /// <summary>
    /// 連線伺服器
    /// </summary>
    /// <returns></returns>
    public static bool Connect()
    {
        if (WebSockets == null)
            return false;
        if (WebSockets.IsAlive)
            return false;
 
        WebSockets.Connect();
        //非同步連線伺服器
        //WebSockets.ConnectAsync();
        //是否接收ping
        //WebSockets.EmitOnPing = true;
 
        //連線狀態可以參考列舉:ReadyState
        if (WebSockets.IsAlive)
        {
            IsClose = false;
            Timer.Enabled = true;
            return true;
        }
        return false;
    }
 
    /// <summary>
    /// 關閉伺服器連線 
    /// </summary>
    /// <returns></returns>
    public static bool Disconnect()
    {
        if (WebSockets == null)
            return false;
 
        WebSockets.Close();
        //非同步關閉
        //WebSockets.CloseAsync();
 
        Timer.Enabled = false;
        IsClose = true;
 
        return WebSockets.IsAlive == false;
    }
 
    #endregion
 
    #region 傳送訊息
 
    /// <summary>
    /// 傳送訊息
    /// </summary>
    /// <param name="message"></param>
    public static void Send(string message)
    {
        if (string.IsNullOrEmpty(message))
        {
            Console.WriteLine("[NetManager]傳送的訊息不能為空");
            return;
        }
        if (WebSockets == null || !WebSockets.IsAlive)
        {
            Console.WriteLine("[NetManager]請先開啟伺服器");
            return;
        }
 
        WebSockets.Send(message);
        //非同步傳送
        //completed 是一個委託,傳送完成會呼叫
        //WebSockets.SendAsync(data, completed);
 
        Console.WriteLine("[NetManager]傳送:" + message);
    }
 
    #endregion
 
    #region 斷線重連
 
    //是否正在重新連線中  
    private static bool IsReconnectioning = false;
 
    private static async void DisconnectionReconnects()
    {
        if (IsReconnectioning) return;
 
        IsReconnectioning = true;
 
        while (true)
        {
            if (WebSockets.IsAlive)
            {
                Console.WriteLine("[NetManager]斷線重連成功");
                IsReconnectioning = false;
                break;
            }
            if (IsClose)
            {
                Console.WriteLine("[NetManager]關閉連線不必斷線重連");
                break;
            }
 
            Console.WriteLine("[NetManager]斷線重連中......");
            WebSockets.Connect();
            //WebSockets.ConnectAsync();
            await Task.Delay(TimeSpan.FromSeconds(1));
        }
    }
 
    #endregion
 
    #region 建構函式
 
    static NetManager()
    {
        Init();
    }
 
    private NetManager() { }
 
    #endregion
}
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace WebSocketSharpClient
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            NetManager.OnMessage = OnMessage;           
        }
 
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            NetManager.Disconnect();
        }
 
        private void OnMessage(string msg)
        {
            Console.WriteLine("收到訊息:" + msg);
        }
 
        private void Button_Send_Click(object sender, EventArgs e)
        {
            string msg = TextBox_Content.Text;
            NetManager.Send(msg);
        }
 
 
        private void Button_Close_Click(object sender, EventArgs e)
        {
            NetManager.Disconnect();
        }
 
        private void Button_Connect_Click(object sender, EventArgs e)
        {
            NetManager.Connect();
        }
    }
}

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



相關文章