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 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 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 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 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 byteReal = new ArraySegment(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 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(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 byteReal = new ArraySegment(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(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(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 callback) //{ //await m_wSocket.SendAsync(new ArraySegment(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 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 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> actions = msgResponseDic[socketCode]; for (int i = 0; i < actions.Count; i++) { actions[i](temp[1]); } msgResponseDic.Remove(socketCode); } if (msgListenerDic.ContainsKey(socketCode)) { List> 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 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 retReadSockets = new List(); 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 callback) { if (msgListenerDic.ContainsKey(socketCode)) { List> 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> actions = new List>(); actions.Add(callback); msgListenerDic.Add(socketCode, actions); } } public void RemoveListener(SocketCode socketCode, Action callback) { if (msgListenerDic.ContainsKey(socketCode)) { List> 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 callback) { if (callback != null) { if (msgResponseDic.ContainsKey(socketCode)) { msgResponseDic[socketCode].Add(callback); } else { List> actions = new List>(); 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> actions = msgResponseDic[socketCode]; for (int i = 0; i < actions.Count; i++) { actions[i](temp[1]); } msgResponseDic.Remove(socketCode); } if (msgListenerDic.ContainsKey(socketCode)) { List> 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(); } }//*/