C# WebSocket 【使用WebSocketSharp实现】
一、概述
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