Files
AIC-Project/Client/Assets/Script/xmain/Manager/lsocket.cs
T
2026-07-10 10:24:29 +08:00

720 lines
23 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using UnityEngine;
using System.Net.WebSockets;
using System.Threading;
using UnityEngine.Networking.PlayerConnection;
using System.Text;
using UnityWebSocket;
using WebSocketState = System.Net.WebSockets.WebSocketState;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
namespace XGame
{
public class XWebSocket
{
private IWebSocket m_WebSocket;//第三方webGL库
string m_Url;
private Socket m_TcpSocket = null;
private Thread m_TcpThread = null;
private bool m_UseTcp = false;
private readonly object m_BufferLock = new object();
private Action<XWebSocket, string> m_Callback = null;
public ClientWebSocket m_wSocket;
public CancellationToken m_Token;
private bool m_bRun = false;
private byte[] m_byteBuffer = new byte[65536];
private byte[] m_byteTemp = new byte[4096];
private ArraySegment<byte> m_bufSegment;
private int m_bufCurPos = 0;
//float heartTime = 0;
//float receiveMsgTime = 0;
//float reconnectCount = 0;
public bool IsConected()
{
if (m_bRun && ((m_UseTcp && m_TcpSocket != null) || (!m_UseTcp && m_WebSocket != null)))
return true;
else
return false;
}
public int GetRecvSize() { lock (m_BufferLock) { return m_bufCurPos; } }
public bool isDataRecv() { lock (m_BufferLock) { return (m_bufCurPos > 0) ? true : false; } }
public void Connect(string url, Action<XWebSocket, string> callback)
{
m_Url = url;
m_Callback = callback;
//m_Url = "wss://echo.websocket.events";
m_bRun = true;
m_WebSocket = new UnityWebSocket.WebSocket(m_Url);
m_WebSocket.OnOpen += Socket_OnOpen;
m_WebSocket.OnMessage += Socket_OnMessage;
m_WebSocket.OnClose += Socket_OnClose;
m_WebSocket.OnError += Socket_OnError;
m_WebSocket.ConnectAsync();
}
public void ConnectTcp(string host, int port, Action<XWebSocket, string> callback)
{
m_UseTcp = true;
m_Url = $"{host}:{port}";
m_Callback = callback;
try
{
m_TcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_TcpSocket.Connect(host, port);
m_bRun = true;
m_TcpThread = new Thread(TcpReceiveLoop);
m_TcpThread.IsBackground = true;
m_TcpThread.Start();
Debug.Log($"Connected tcp://{m_Url}");
m_Callback(this, null);
}
catch (Exception e)
{
m_bRun = false;
Debug.Log($"Tcp connect error: {e.Message}");
m_Callback(null, e.Message);
}
}
public void Socket_OnOpen(object sender, OpenEventArgs e)
{
if (e != null)
Debug.Log($"Connected {m_Url} Result : {sender.ToString()}");
else
Debug.Log(string.Format("Connected: {0}", m_Url));
m_Callback(this, null);
}
public void Socket_OnMessage(object sender, UnityWebSocket.MessageEventArgs e)
{
//if (e.IsBinary)
//{
// Debug.Log(string.Format("C# Receive Bytes ({1}): {0}", e.Data, e.RawData.Length));
//}
//else if (e.IsText)
//{
// Debug.Log(string.Format("C# Receive: {0}", e.Data));
//}
//ArraySegment<byte> byteReal = new ArraySegment<byte>(m_byteTemp);
//Debug.Log($"Buffer = {m_byteTemp.Length} ; Segment = {byteReal.Count}");
//复制到m_byteBuffer
AddBuffer(e.RawData);
//receiveCount += 1;
}
public void Socket_OnClose(object sender, CloseEventArgs e)
{
m_bRun = false;
Debug.Log(string.Format("Closed: StatusCode: {0}, Reason: {1}", e.StatusCode, e.Reason));
}
public void Socket_OnError(object sender, ErrorEventArgs e)
{
m_bRun = false;
Debug.Log(string.Format("Error: {0}", e.Message));
}
//public async void Connect(string addr, int port, Action<XWebSocket, string> callback)
//{
// m_wSocket = new ClientWebSocket();
// m_Token = new CancellationToken();
// Uri url = new Uri("wss://echo.websocket.events");//"ws://121.40.165.18:8800");// $"ws://{addr}:{port}/xxx/xxx");
// Debug.Log($"CS Connect {url.ToString()}");
// m_bufSegment = new ArraySegment<byte>(m_byteBuffer);
// await m_wSocket.ConnectAsync(url, m_Token);
// if (m_wSocket.State == WebSocketState.Open)
// {
// Debug.Log($"--------连接成功 : {url.ToString()}");
// m_bRun = true;
// callback(this, null);
// }
// else
// {
// Debug.Log($"--------连接失败 : {url.ToString()}");
// callback(this, $"Connect Error : {m_wSocket.State}");
// }
// while (m_bRun)
// {
// //var result = new byte[1024];
// ArraySegment<byte> byteReal = new ArraySegment<byte>(m_byteTemp);
// WebSocketReceiveResult result = await m_wSocket.ReceiveAsync(byteReal, new CancellationToken());//接受数据
// Debug.Log($"Buffer = {m_byteTemp.Length} ; Segment = {byteReal.Count}");
// //复制到m_byteBuffer
// AddBuffer(byteReal);
// //var str = Encoding.UTF8.GetString(m_byteTemp, 0, m_byteTemp.Length);
// //Debug.Log(str);
// }
//}
void AddBuffer(byte[] buffer)
{
lock (m_BufferLock)
{
if (m_bufCurPos + buffer.Length > m_byteBuffer.Length)
{
m_bufCurPos = 0;
}
Array.ConstrainedCopy(buffer, 0, m_byteBuffer, m_bufCurPos, buffer.Length);
m_bufCurPos = m_bufCurPos + buffer.Length;
m_bufSegment = new ArraySegment<byte>(m_byteBuffer, 0, m_bufCurPos);
}
}
public byte[] GetBuffer()
{
lock (m_BufferLock)
{
return m_bufSegment.ToArray();
}
}
public byte[] recv(ref string errorMsg)
{
if (!m_bRun)
{//已经断线了
errorMsg = null;
Debug.Log($"net disconnected !");
return null;
}
if (m_bufCurPos == 0)
{//不需要获取数据
errorMsg = "";
return null;
}
byte[] retBuf;
lock (m_BufferLock)
{
retBuf = m_bufSegment.ToArray();
m_bufCurPos = 0;
m_bufSegment = new ArraySegment<byte>(m_byteBuffer, 0, 0);
}
//Debug.Log($"c# recv: {retBuf.Length}");
return retBuf;
}
public byte[] Recv(ref string errorMsg)
{
return recv(ref errorMsg);
}
//async void SendAsync(byte[] sendData, Action<int, string> callback)
//{
//await m_wSocket.SendAsync(new ArraySegment<byte>(sendData), WebSocketMessageType.Binary, false, m_Token);
//if (m_wSocket.State != WebSocketState.Open)
//{
// callback(0, null);
//}
//else
// callback(sendData.Length, null);
//}
public int send(byte[] sendData, Action<int, string> callback, ref string errorMsg )
{
//Debug.Log($"c# send {sendData.Length}");加入了consoleWindows后不能再这里打印
if (m_UseTcp)
{
int sent = 0;
while (sent < sendData.Length)
{
sent += m_TcpSocket.Send(sendData, sent, sendData.Length - sent, SocketFlags.None);
}
}
else
{
m_WebSocket.SendAsync(sendData);
}
errorMsg = null;
return sendData.Length;
}
public int Send(byte[] sendData, Action<int, string> callback, ref string errorMsg)
{
return send(sendData, callback, ref errorMsg);
}
public void close()
{
m_bRun = false;
if (m_UseTcp)
{
m_TcpSocket?.Close();
}
else
{
m_WebSocket.CloseAsync();
}
}
public bool status(ref string errorMsg)
{
return m_bRun;
}
public void settimeout(int timeout)
{
}
private void TcpReceiveLoop()
{
byte[] buffer = new byte[4096];
while (m_bRun)
{
try
{
int count = m_TcpSocket.Receive(buffer);
if (count <= 0)
{
break;
}
byte[] data = new byte[count];
Array.ConstrainedCopy(buffer, 0, data, 0, count);
AddBuffer(data);
Debug.Log($"Tcp received {count} bytes");
}
catch (Exception e)
{
if (m_bRun)
{
Debug.Log($"Tcp receive error: {e.Message}");
}
break;
}
}
m_bRun = false;
}
/*
private void WebSocketReceive(object sender, MessageEventArgs e)
{
//优化逻辑
//heartTime = 0;
receiveMsgTime = Time.realtimeSinceStartup;
if (e.IsText)
{
string[] temp = e.Data.Split('.');
//发送接口需要返回的消息
SocketCode socketCode = (SocketCode)int.Parse(temp[0]);
if (msgResponseDic.ContainsKey(socketCode))
{
List<Action<string>> actions = msgResponseDic[socketCode];
for (int i = 0; i < actions.Count; i++)
{
actions[i](temp[1]);
}
msgResponseDic.Remove(socketCode);
}
if (msgListenerDic.ContainsKey(socketCode))
{
List<Action<string>> actions = msgListenerDic[socketCode];
for (int i = 0; i < actions.Count; i++)
{
actions[i](temp[1]);
}
}
Debug.LogError(string.Format("接收到消息: {0}", e.Data));
}
else if (e.IsBinary)
{
Debug.LogError(string.Format("接受到消息 Bytes ({1}): {0}", e.Data, e.RawData.Length));
}
}
private void WebSocketError(object sender, ErrorEventArgs e)
{
connected = false;
throw new NotImplementedException();
}
private void WebSocketOpen(object sender, OpenEventArgs e)
{
reconnectCount = 0;
receiveMsgTime = Time.realtimeSinceStartup;
connected = true;
Debug.LogError(string.Format("连接成功,IP:{0}", ip));
}
private void WebSocketClose(object sender, CloseEventArgs e)
{
connected = false;
Debug.LogError(string.Format("连接关闭: StatusCode: {0}, Reason: {1}", e.StatusCode, e.Reason));
}//*/
}
public class lsocket : MonoBehaviour
{
//private WebSocket m_wSocket = new WebSocket();
public lsocket Instance;
private void Awake()
{
Instance = this;
}
public static float gettime()
{
return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000;
}
//外部接口
public static void connect(string addr, int port, Action<XWebSocket, string> callback )
{
XWebSocket socket = new XWebSocket();
bool forceTcp = false;
if (addr.StartsWith("http://"))
addr = addr.Substring("http://".Length);
else if (addr.StartsWith("https://"))
addr = addr.Substring("https://".Length);
else if (addr.StartsWith("tcp://"))
{
addr = addr.Substring("tcp://".Length);
forceTcp = true;
}
if (!addr.StartsWith("ws://") && !addr.StartsWith("wss://"))
{
int slash = addr.IndexOf("/");
if (slash >= 0)
addr = addr.Substring(0, slash);
string host = addr;
int tcpPort = port;
int colon = addr.LastIndexOf(":");
if (colon >= 0)
{
host = addr.Substring(0, colon);
int.TryParse(addr.Substring(colon + 1), out tcpPort);
}
if (forceTcp || host == "localhost" || host == "127.0.0.1" || tcpPort == 7777 || tcpPort == 7788)
{
Debug.Log($"C# Connect tcp://{host}:{tcpPort}");
socket.ConnectTcp(host, tcpPort, callback);
return;
}
}
if (addr.StartsWith("ws://") || addr.StartsWith("wss://"))
{
if (port != 0)
addr = $"{addr}:{port}";
Debug.Log($"C# Connect {addr}");
socket.Connect(addr, callback);
return;
}
//socket.Connect(addr, port, callback);
//if (port != 0)
int pos = addr.IndexOf(":");
string str;
if (pos == -1)
str = addr;
else
str = addr.Substring(0, pos);
string regexStrIPV4 = (@"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$");
if (Regex.IsMatch(str, regexStrIPV4) && addr != "0.0.0.0")
{//ip用ws
addr = $"ws://{addr}";
}
else
{//域名的用wss
addr = $"wss://{addr}";
if (port != 0)
port += 2000;//wss连接的端口规则
}
// if (!addr.StartsWith("wss://") && !addr.StartsWith("ws://"))
// {
//#if UNITY_EDITOR
// addr = $"ws://{addr}";
//#else
// if(!LoadDll.m_bInWX)
// {
// addr = $"wss://{addr}";
// if(port != 0)
// port += 2000;//wss连接的端口规则
// }
// else
// {
// addr = $"wss://{addr}";
// if(port != 0)
// port += 2000;//wss连接的端口规则
// }
//#endif
// //addr = $"ws://{addr}";
// }
if (port != 0)
addr = $"{addr}:{port}";
//addr = "wss://g7h5.guangyv.com:4201";
Debug.Log($"C# Connect {addr}");
socket.Connect(addr, callback);
}
//传入多个WebSocket引用,返回有数据处理的, dataSize为零就不需要处理
public static XWebSocket[] select(XWebSocket[] readSockets, XWebSocket[] writeSockets, int Param, ref XWebSocket[] retWriteSockets, ref int dataSize)
{
List<XWebSocket> retReadSockets = new List<XWebSocket>();
string error = null;
bool bOK = true;
dataSize = 0;
for (int i = 0; i < readSockets.Length; ++i)
{
if (!readSockets[i].status(ref error))
{
bOK = false;
break;
}
int recvSize = readSockets[i].GetRecvSize();
if (recvSize > 0)
{
retReadSockets.Add(readSockets[i]);
dataSize += recvSize;
}
}
if (!bOK)
return null;
retWriteSockets = writeSockets;
return retReadSockets.ToArray();
}
}
}
/*
public class WebSocketLogic : MonoBehaviour
{
public async void WebSocket()
{
try
{
ClientWebSocket ws = new ClientWebSocket();
CancellationToken ct = new CancellationToken();
//添加header
//ws.Options.SetRequestHeader("X-Token", "eyJhbGciOiJIUzI1N");
Uri url = new Uri("ws://121.40.165.18:8800/v1/test/test");
await ws.ConnectAsync(url, ct);
await ws.SendAsync(new ArraySegment(Encoding.UTF8.GetBytes("hello")), WebSocketMessageType.Binary, true, ct); //发送数据
while (true)
{
var result = new byte[1024];
await ws.ReceiveAsync(new ArraySegment(result), new CancellationToken());//接受数据
var str = Encoding.UTF8.GetString(result, 0, result.Length);
Debug.Log(str);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private WebSocketLogic() { }
private WebSocketLogic _instance;
public WebSocketLogic Instance
{
get
{
if (_instance == null)
{
_instance = new WebSocketLogic();
}
return _instance;
}
private set { }
}
WebSocket webSocket;
string ip;
public void Init(string _ip)
{
inited = true;
ip = _ip;
}
public void Connect()
{
RemoveHandle();
webSocket = new WebSocket(ip);
webSocket.OnClose += WebSocketClose;
webSocket.OnOpen += WebSocketOpen;
webSocket.OnError += WebSocketError;
webSocket.OnMessage += WebSocketReceive;
webSocket.ConnectAsync();
}
public void AddListener(SocketCode socketCode, Action<string> callback)
{
if (msgListenerDic.ContainsKey(socketCode))
{
List<Action<string>> actions = msgListenerDic[socketCode];
for (int i = 0; i < actions.Count; i++)
{
if (actions[i] == callback)
{
Debug.LogError("重复注册监听,消息号:" + socketCode);
return;
}
}
msgListenerDic[socketCode].Add(callback);
}
else
{
List<Action<string>> actions = new List<Action<string>>();
actions.Add(callback);
msgListenerDic.Add(socketCode, actions);
}
}
public void RemoveListener(SocketCode socketCode, Action<string> callback)
{
if (msgListenerDic.ContainsKey(socketCode))
{
List<Action<string>> actions = msgListenerDic[socketCode];
for (int i = 0; i < actions.Count; i++)
{
if (actions[i] == callback)
{
actions.RemoveAt(i);
return;
}
}
Debug.LogError("移除监听出错,未包注册监听消息函数,消息号:" + socketCode);
}
else
{
Debug.LogError("移除监听出错,未包注册监听,消息号:" + socketCode);
}
}
void RemoveHandle()
{
msgResponseDic.Clear();
webSocket = null;
webSocket.OnClose -= WebSocketClose;
webSocket.OnOpen -= WebSocketOpen;
webSocket.OnError -= WebSocketError;
webSocket.OnMessage -= WebSocketReceive;
}
public void Send(SocketCode socketCode, string msg, Action<string> callback)
{
if (callback != null)
{
if (msgResponseDic.ContainsKey(socketCode))
{
msgResponseDic[socketCode].Add(callback);
}
else
{
List<Action<string>> actions = new List<Action<string>>();
actions.Add(callback);
msgResponseDic.Add(socketCode, actions);
}
}
webSocket.SendAsync(string.Format("{0}/{1}", socketCode, msg));
}
private void WebSocketReceive(object sender, MessageEventArgs e)
{
//优化逻辑
//heartTime = 0;
receiveMsgTime = Time.realtimeSinceStartup;
if (e.IsText)
{
string[] temp = e.Data.Split('.');
//发送接口需要返回的消息
SocketCode socketCode = (SocketCode)int.Parse(temp[0]);
if (msgResponseDic.ContainsKey(socketCode))
{
List<Action<string>> actions = msgResponseDic[socketCode];
for (int i = 0; i < actions.Count; i++)
{
actions[i](temp[1]);
}
msgResponseDic.Remove(socketCode);
}
if (msgListenerDic.ContainsKey(socketCode))
{
List<Action<string>> actions = msgListenerDic[socketCode];
for (int i = 0; i < actions.Count; i++)
{
actions[i](temp[1]);
}
}
Debug.LogError(string.Format("接收到消息: {0}", e.Data));
}
else if (e.IsBinary)
{
Debug.LogError(string.Format("接受到消息 Bytes ({1}): {0}", e.Data, e.RawData.Length));
}
}
private void WebSocketError(object sender, ErrorEventArgs e)
{
connected = false;
throw new NotImplementedException();
}
private void WebSocketOpen(object sender, OpenEventArgs e)
{
reconnectCount = 0;
receiveMsgTime = Time.realtimeSinceStartup;
connected = true;
Debug.LogError(string.Format("连接成功,IP:{0}", ip));
}
private void WebSocketClose(object sender, CloseEventArgs e)
{
connected = false;
Debug.LogError(string.Format("连接关闭: StatusCode: {0}, Reason: {1}", e.StatusCode, e.Reason));
}
float heartTime = 0;
float receiveMsgTime = 0;
float reconnectCount = 0;
private void Update()
{
if (!inited)
{
return;
}
heartTime = heartTime + Time.deltaTime;
if (heartTime >= 5.0f && connected == true)
{
heartTime = 0.0f;
Send(SocketCode.Heart, "heartbeat", null);
}
if (receiveMsgTime != 0 && Time.realtimeSinceStartup - receiveMsgTime > 6.0f)
{
if (reconnectCount > 5)
{
Debug.LogError("重新连接失败!");
return;
}
receiveMsgTime = Time.realtimeSinceStartup;
connected = false;
webSocket.CloseAsync();
Connect();
reconnectCount = reconnectCount + 1;
Debug.LogError(string.Format("连接断开,尝试第{0}次重新连接!", reconnectCount));
}
}
public void Clear()
{
connected = false;
inited = false;
msgResponseDic.Clear();
msgListenerDic.Clear();
}
}//*/