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;
}
}
}
}
}