一、概述
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