using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading; public class ClientSocketController { Socket m_Socket; public Socket socket { get { return m_Socket; } } private int connectWaitTime = 2000; // 10秒 private Thread m_packageThread; private byte[] bufferBytes = new byte[4096]; // 4K,单包字节数组缓存 private byte[] fragmentBytes; //留包后的内容 private long getBytesTotal = 0; //发送的数据总量 private long sendBytesTotal = 0; //发送的数据总量 public bool Connected { get { return m_Socket == null ? false : m_Socket.Connected; } } public bool isStopTreading { get; private set; } string ip; int port; Action onConnected = null; public ClientSocketController() { } public void Connect(string _ip, int _port, Action _onConnected) { try { ip = _ip; port = _port; onConnected = _onConnected; Dns.BeginGetHostAddresses(_ip, OnGetHostAddresses, null); } catch (Exception e) { DebugEx.LogError(e.Message); } } private void OnGetHostAddresses(IAsyncResult _result) { var ipAddresses = Dns.EndGetHostAddresses(_result); if (ipAddresses[0].AddressFamily == AddressFamily.InterNetworkV6) { DebugEx.Log("当前使用的网络: IPV6"); m_Socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); } else { DebugEx.Log("当前使用的网络: IPV4"); m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); } var ipEndPoint = new IPEndPoint(ipAddresses[0], port); if (ipEndPoint == null) { Debug.Log("IpEndPoint is null"); } var state = new SocketAsyncState(); state.IsAsync = true; m_Socket.BeginConnect(ipEndPoint, new AsyncCallback(ConnectCallBack), state); } /// /// 链接成功时的回调 /// /// private void ConnectCallBack(IAsyncResult _result) { if (!_result.IsCompleted) { DebugEx.Log("链接超时!"); CloseConnect(); } else { if (m_Socket != null && m_Socket.Connected) { DebugEx.Log("确认的链接实现"); OnConnectSuccess(); if (onConnected != null) { onConnected(); onConnected = null; } } else { if (m_Socket != null) { m_Socket.Disconnect(true); } onConnected = null; } } } /// /// 关闭链接 /// public void CloseConnect() { try { isStopTreading = true; if (m_packageThread != null) { m_packageThread.Abort(); } } catch (System.Exception ex) { DebugEx.Log(ex); } try { if (m_Socket != null && m_Socket.Connected) { m_Socket.Shutdown(SocketShutdown.Both); m_Socket.Close(); } } catch (System.Exception ex) { DebugEx.Log(ex); } sendQueue.Clear(); m_Socket = null; } /// /// 链接成功 /// private void OnConnectSuccess() { if (m_packageThread != null) { m_packageThread.Abort(); m_packageThread = null; } m_packageThread = new Thread(new ThreadStart(ReceiveInfo)); // 启动线程接收信息 m_packageThread.IsBackground = true; m_packageThread.Start(); isStopTreading = false; } /// /// 接收信息 /// private void ReceiveInfo() { int vDataLeng; byte[] vBytes; while (!isStopTreading) { if (!m_Socket.Connected) { isStopTreading = true; m_Socket.Shutdown(SocketShutdown.Both); m_Socket.Close(); break; } try { vDataLeng = m_Socket.Receive(bufferBytes); if (vDataLeng <= 0) { isStopTreading = true; m_Socket.Shutdown(SocketShutdown.Both); m_Socket.Close(); break; } getBytesTotal += vDataLeng; vBytes = new byte[vDataLeng]; Array.Copy(bufferBytes, 0, vBytes, 0, vDataLeng); ReadInfo(vBytes); } catch (Exception e) { DebugEx.Log(e); } } } static byte[] vCmdBytes = new byte[2]; /// /// 阅读信息 /// /// private void ReadInfo(byte[] vBytes) { try { byte[] fixBytes = vBytes; // 如果存在留包,则并包 if (fragmentBytes != null && fragmentBytes.Length > 0) { Array.Resize(ref fixBytes, vBytes.Length + fragmentBytes.Length); Array.Copy(fragmentBytes, 0, fixBytes, 0, fragmentBytes.Length); Array.Copy(vBytes, 0, fixBytes, fragmentBytes.Length, vBytes.Length); } fragmentBytes = null; // 清理掉留包 // 分包 int vReadIndex = 0; // 初始指针 byte[] vPackBytes; int vLeavingLeng = 0; int vBodyLeng = 0; int vTotalLeng = fixBytes.Length; GameNetPackBasic vNetpack; while (vReadIndex < vTotalLeng) { vLeavingLeng = vTotalLeng - vReadIndex; if (vLeavingLeng < 6) // 未符合包的最低限度字节量, 留包 { fragmentBytes = new byte[vLeavingLeng]; Array.Copy(fixBytes, vReadIndex, fragmentBytes, 0, vLeavingLeng); break; } vBodyLeng = BitConverter.ToInt32(fixBytes, vReadIndex + 2); if (vBodyLeng > vLeavingLeng - 6)// 未完整的包则留包 { fragmentBytes = new byte[vLeavingLeng]; Array.Copy(fixBytes, vReadIndex, fragmentBytes, 0, vLeavingLeng); break; } vPackBytes = new byte[vBodyLeng]; Array.Copy(fixBytes, vReadIndex + 6, vPackBytes, 0, vBodyLeng); // 提取包的字节内容 // 完整的包则读包 vPackBytes = GameNetEncode.BaseXorSub(vPackBytes); Array.Copy(vPackBytes, 0, vCmdBytes, 0, 2); var cmd = (ushort)((ushort)(vCmdBytes[0] << 8) + vCmdBytes[1]); if (PackageRegedit.Contain(cmd)) { vNetpack = PackageRegedit.TransPack(cmd, vPackBytes); if (vNetpack != null) { if (DebugEx.EnableNetLog) { DebugEx.NetLogFormat("收包:{0}", vNetpack.GetType().Name); } GameNetSystem.Instance.PushPackage(vNetpack); } } else { CSharpCallLua.OnRecieveLuaNetPackage(cmd, vPackBytes); } vReadIndex += 6 + vBodyLeng; } } catch (Exception ex) { Debug.LogFormat("收包异常:{0}", ex); } } /// /// 发送信息 /// /// public void SendInfo(GameNetPackBasic vNetPack) { if (!Connected) return; if (vNetPack == null) { DebugEx.LogError("要发的信息对象为空"); return; } if (DebugEx.EnableNetLog) { DebugEx.NetLogFormat("发包:{0}", vNetPack.GetType().Name); } if (vNetPack.cmd == (ushort)0x03FE || vNetPack.cmd == (ushort)0x1801) { } if (vNetPack.combineBytes == null) { vNetPack.WriteToBytes(); } vNetPack.CombineDatas(); #if UNITY_EDITOR NetPkgCtl.AddNetPkg(vNetPack.vInfoCont, NetPkgType.Client, vNetPack.ToString(), FieldPrint.PrintFields(vNetPack), FieldPrint.PrintFieldsExpand(vNetPack, true)); #endif sendBytesTotal += vNetPack.combineBytes.Length; SendBytes(vNetPack.combineBytes); } /// /// 发送信息 /// /// public void SendInfo(byte[] vBytes) { if (!Connected) { DebugEx.LogError("尚未与该后端链接!无法发送信息"); return; } if (vBytes == null || vBytes.Length < 2) { DebugEx.LogError("要发的信息数据为空或数据不足"); return; } vBytes = GameNetEncode.BaseXorAdd(vBytes); byte[] vFrameHead = new byte[] { 255, 204 }; byte[] vMsgBodyLength = BitConverter.GetBytes(vBytes.Length); byte[] vTotal = new byte[vBytes.Length + 6]; Array.Copy(vFrameHead, 0, vTotal, 0, vFrameHead.Length); Array.Copy(vMsgBodyLength, 0, vTotal, 2, vMsgBodyLength.Length); Array.Copy(vBytes, 0, vTotal, 6, vBytes.Length); SendBytes(vTotal); } /// /// 发送已加密字节 /// /// public void SendNoEncrypInfo(byte[] vBytes) { if (!Connected) { DebugEx.LogError("尚未与该后端链接!无法发送信息"); return; } if (vBytes == null || vBytes.Length < 2) { DebugEx.LogError("要发的信息数据为空或数据不足"); return; } SendBytes(vBytes); } Queue sendQueue = new Queue(); private void SendBytes(byte[] bytes) { try { if (sendQueue.Count > 0) { sendQueue.Enqueue(bytes); } else { m_Socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, new AsyncCallback(SendInfoCallBack), m_Socket); } } catch { DebugEx.LogError("发送时发生异常"); } } /// /// 发送完成的回调 /// /// private void SendInfoCallBack(IAsyncResult vAsyncSend) { try { if (sendQueue.Count > 0) { var bytes = sendQueue.Dequeue(); m_Socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, new AsyncCallback(SendInfoCallBack), m_Socket); } } catch (Exception ex) { DebugEx.Log(ex); } } internal class SocketAsyncState { /// /// 是否完成。 /// public bool Completed { get; set; } /// /// 数据 /// public byte[] Data { get; set; } /// /// 是否异步 /// public bool IsAsync { get; set; } } }