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

 

 

 

 

 



posted @ 2024-11-06 19:41  【君莫笑】  阅读(833)  评论(0编辑  收藏  举报