【网络&WebSocket】WebSocket&C# 客户端连接

发布于:2025-07-01 ⋅ 阅读:(27) ⋅ 点赞:(0)

using System;
using System.IO;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;

public class Server_Manager_ : MonoBehaviour
{   

    private static Server_Manager_ instance;
    public static Server_Manager_ Instance
    {
        get
        {
            if(instance == null)
            {
                Debug.Log("Server_Manager_ is not initialized.");
            }    

            return instance;
        }
    }

    private void Awake()
    {
        if(instance != null && instance != this)
        {
            Destroy(gameObject);
            return;
        }

        instance = this;

        DontDestroyOnLoad(gameObject);
    }

    private CancellationTokenSource cancellationTokenSource;//用于取消异步操作的对象
    [SerializeField] private string url_Str = null;//创建
    private Uri uri;
    private ClientWebSocket webSocket;

    //同步锁
    private readonly object lock_ = new object();
        
    //异步Start,连接WebSocket
    private async void Start()
    {
        await EnterStartWebSocket();
    }

    /// <summary>
    /// 连接WebSocket的入口方法
    /// </summary>
    /// <returns></returns>
    public async Task EnterStartWebSocket()
    {   
        //取消旧的WebSocket接收循环
        //清理资源,防止内存泄漏
        //保证新启动的是干净的连接流程
        if (cancellationTokenSource != null)
        {   
            try
            {
                cancellationTokenSource.Cancel();
                cancellationTokenSource.Dispose();
            }
            catch (Exception e)
            {
                Debug.LogException(e);
            }
        }

        //创建新的WebSocket连接
        cancellationTokenSource = new CancellationTokenSource();

        //启动
        await StartWebSocket();
    }

    /// <summary>
    /// 连接服务器
    /// </summary>
    /// <returns></returns>
    public async Task StartWebSocket()
    {   
        //判断是否
        if(string.IsNullOrEmpty(url_Str))
        {

        }

        //若没有收到令牌对象取消通知,则循环如下操作
        while (!cancellationTokenSource.Token.IsCancellationRequested)
        {
            try
            {
                #region 连接
                //如果未初始化WebSocket或连接已断开,则创建新实例
                if (webSocket == null || webSocket.State != WebSocketState.Open)
                {
                    lock (lock_)
                    {
                        webSocket?.Dispose();//清理旧实例
                        webSocket = new ClientWebSocket();//创建新连接
                    }

                    //创建URI并连接服务器
                    uri = new Uri(url_Str);

                    //连接
                    await webSocket.ConnectAsync(uri, cancellationTokenSource.Token);
                    Debug.Log("WebSocket connected successfully");
                }
                #endregion

                #region 接收消息&处理消息
                //在WebSocket实例处于打开状态且还未接收到取消对象的取消任务时,开始循环地接收消息
                while (webSocket.State == WebSocketState.Open && !cancellationTokenSource.Token.IsCancellationRequested)
                {   
                    //使用内存流暂存所有接收到的片段,using的调用可以在结束后自动触发memoryStream.Dispose()
                    using (var memoryStream = new MemoryStream())
                    {
                        #region 接收消息至缓存区
                        WebSocketReceiveResult receiveResult;//声明一个接收结果的对象
                        byte[] buffer = new byte[4096];//设置缓存区的大小

                        //处理分片消息,直到消息接收完整
                        do
                        {
                            receiveResult = await webSocket.ReceiveAsync(
                                new ArraySegment<byte>(buffer),
                                cancellationTokenSource.Token
                                );

                            //如果接收到来自服务端的关闭控制消息,则结束接收循环
                            if(receiveResult.MessageType == WebSocketMessageType.Close)
                            {
                                Debug.Log("Close message received from server");
                                //关闭连接
                                await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure,
                                    string.Empty,
                                    cancellationTokenSource.Token);

                                break;
                            }

                            //将接收到的数据片段写入内存流
                            memoryStream.Write(buffer, 0, receiveResult.Count);
                        }
                        while (!receiveResult.EndOfMessage);//直到消息接收完整

                        //将所有数据从内存流提取为byte[]
                        byte[] receivedData = memoryStream.ToArray();
                        #endregion

                        #region 处理消息
                        //处理文本消息
                        if (receiveResult.MessageType == WebSocketMessageType.Text)
                        {
                            try
                            {
                                Debug.Log("接收到了文本数据");
                                //TODO:在此处理文本数据
                            }
                            catch(Exception e)
                            {
                                Debug.LogError(e.Message);
                                Debug.LogError("原始数据" + Encoding.UTF8.GetString(receivedData));
                            }
                        }
                        else if(receiveResult.MessageType == WebSocketMessageType.Binary)
                        {
                            Debug.Log("接收到了二进制数据");
                            //TODO:在此处理二进制数据    
                        }
                        #endregion
                    }
                }
                #endregion
            }
            catch (Exception e)
            {
                //处理异常消息
                Debug.LogError(e.Message);

                //安全关闭并清理旧连接
                lock(lock_)
                {
                    webSocket?.Dispose();
                    webSocket = null;
                }

                //如果已经取消,就跳出循环不在
                if(cancellationTokenSource == null || cancellationTokenSource.Token.IsCancellationRequested)
                    break;

                try
                {
                    if (cancellationTokenSource == null || cancellationTokenSource.Token.IsCancellationRequested)
                        break;
                    else
                    {
                        //等待5秒后尝试重新连接
                        Debug.Log("尝试5秒后重新连接");
                        await Task.Delay(5000, cancellationTokenSource.Token);
                    }
                }
                catch(TaskCanceledException)
                {
                    break;
                }
            }
        }
    }
}


 


网站公告

今日签到

点亮在社区的每一天
去签到