| using UnityEngine; | 
| using System; | 
| using System.Collections; | 
| using System.Collections.Generic; | 
| using System.Net; | 
| using System.Net.Sockets; | 
| using System.Threading; | 
|   | 
| public class ClientSocket | 
| { | 
|     GameNetEncode encoder = new GameNetEncode(); | 
|     Socket m_Socket; | 
|     public Socket socket { get { return m_Socket; } } | 
|   | 
|     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; } } | 
|   | 
|     ServerType socketType = ServerType.Main; | 
|     DateTime m_LastPackageTime; | 
|     public DateTime lastPackageTime { get { return m_LastPackageTime; } } | 
|   | 
|     bool isStopTreading = false; | 
|   | 
|     string ip; | 
|     int port; | 
|     Action<bool> onConnected = null; | 
|   | 
|     public ClientSocket(ServerType type) | 
|     { | 
|         this.socketType = type; | 
|     } | 
|   | 
|     public void Connect(string _ip, int _port, Action<bool> _onConnected) | 
|     { | 
|         try | 
|         { | 
|             ip = _ip; | 
|             port = _port; | 
|             onConnected = _onConnected; | 
|             //目前测试到异步两个问题 | 
|             // 1. BeginGetHostAddresses 不明情况下会很久才回调,导致触发超时 | 
|             // 2. 超时的情况下多次尝试登录后,会触发多次OnGetHostAddresses,导致登录异常 | 
|             //Dns.BeginGetHostAddresses(_ip, OnGetHostAddresses, null); | 
|   | 
|             IPAddress ipAddress; | 
| #if UNITY_IPHONE | 
|             IPHostEntry ipAddresses = Dns.GetHostEntry(_ip); | 
|             ipAddress = ipAddresses.AddressList[0]; | 
|              | 
| #else | 
|             IPAddress[] ipAddresses = Dns.GetHostAddresses(_ip); | 
|             ipAddress = ipAddresses[0]; | 
| #endif | 
|   | 
|   | 
|             if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6) | 
|             { | 
|                 Debug.Log("当前使用的网络: IPV6"); | 
|                 m_Socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); | 
|             } | 
|             else | 
|             { | 
|                 Debug.Log("当前使用的网络: IPV4"); | 
|                 m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); | 
|             } | 
|   | 
|             var ipEndPoint = new IPEndPoint(ipAddress, port); | 
|             if (ipEndPoint == null) | 
|             { | 
|                 Debug.Log("IpEndPoint is null"); | 
|             } | 
|   | 
|             m_Socket.BeginConnect(ipEndPoint, new AsyncCallback(ConnectCallBack), null); | 
|         } | 
|         catch (Exception e) | 
|         { | 
|             Debug.LogError(e.Message); | 
|         } | 
|   | 
|   | 
|     } | 
|   | 
|     private void OnGetHostAddresses(IAsyncResult _result) | 
|     { | 
|         var ipAddresses = Dns.EndGetHostAddresses(_result); | 
|   | 
|         if (ipAddresses[0].AddressFamily == AddressFamily.InterNetworkV6) | 
|         { | 
|             Debug.Log("当前使用的网络: IPV6"); | 
|             m_Socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); | 
|         } | 
|         else | 
|         { | 
|             Debug.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"); | 
|         } | 
|   | 
|         m_Socket.BeginConnect(ipEndPoint, new AsyncCallback(ConnectCallBack), null); | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 链接成功时的回调 | 
|     /// </summary> | 
|     /// <param name="_result"></param> | 
|     private void ConnectCallBack(IAsyncResult _result) | 
|     { | 
|         if (!_result.IsCompleted) | 
|         { | 
|             Debug.Log("链接超时!"); | 
|             CloseConnect(); | 
|             if (onConnected != null) | 
|             { | 
|                 onConnected(false); | 
|                 onConnected = null; | 
|             } | 
|         } | 
|         else | 
|         { | 
|             try | 
|             { | 
|                 if (m_Socket != null && m_Socket.Connected) | 
|                 { | 
|                     Debug.Log("确认的链接实现"); | 
|                     OnConnectSuccess(); | 
|                 } | 
|                 else | 
|                 { | 
|                     if (m_Socket != null) | 
|                     { | 
|                         m_Socket.Disconnect(true); | 
|                     } | 
|                 } | 
|             } | 
|             catch (System.Exception ex) | 
|             { | 
|                 Debug.Log(ex); | 
|             } | 
|             finally | 
|             { | 
|                 if (onConnected != null) | 
|                 { | 
|                     onConnected(m_Socket != null && m_Socket.Connected); | 
|                     onConnected = null; | 
|                 } | 
|             } | 
|   | 
|         } | 
|   | 
|         onConnected = null; | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 关闭链接 | 
|     /// </summary> | 
|     public void CloseConnect() | 
|     { | 
|         Debug.Log("==== CloseConnect"); | 
|         try | 
|         { | 
|             isStopTreading = true; | 
|             if (m_packageThread != null) | 
|             { | 
|                 m_packageThread.Abort(); | 
|             } | 
|         } | 
|         catch (System.Exception ex) | 
|         { | 
|             Debug.Log(ex); | 
|         } | 
|   | 
|         try | 
|         { | 
|             if (m_Socket != null && m_Socket.Connected) | 
|             { | 
|                 m_Socket.Shutdown(SocketShutdown.Both); | 
|                 m_Socket.Close(); | 
|             } | 
|         } | 
|         catch (System.Exception ex) | 
|         { | 
|             Debug.Log(ex); | 
|         } | 
|   | 
|         sendQueue.Clear(); | 
|         m_Socket = null; | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 链接成功 | 
|     /// </summary> | 
|     private void OnConnectSuccess() | 
|     { | 
|         if (m_packageThread != null) | 
|         { | 
|             m_packageThread.Abort(); | 
|             m_packageThread = null; | 
|         } | 
|   | 
|         m_LastPackageTime = DateTime.Now; | 
|         m_packageThread = new Thread(new ThreadStart(ReceiveInfo)); // 启动线程接收信息 | 
|         m_packageThread.IsBackground = true; | 
|         m_packageThread.Start(); | 
|         isStopTreading = false; | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 接收信息 | 
|     /// </summary> | 
|     private void ReceiveInfo() | 
|     { | 
|         while (!isStopTreading) | 
|         { | 
|             try | 
|             { | 
|                 var shutdown = false; | 
|                 if (!m_Socket.Connected) | 
|                 { | 
|                     shutdown = true; | 
|                 } | 
|   | 
|                 if (!shutdown) | 
|                 { | 
|                     var dataLength = m_Socket.Receive(bufferBytes); | 
|                     if (dataLength <= 0) | 
|                     { | 
|                         shutdown = true; | 
|                     } | 
|                     else | 
|                     { | 
|                         getBytesTotal += dataLength; | 
|                         var bytes = new byte[dataLength]; | 
|                         Array.Copy(bufferBytes, 0, bytes, 0, dataLength); | 
|                         ReadInfo(bytes); | 
|                     } | 
|                 } | 
|   | 
|                 if (shutdown) | 
|                 { | 
|                     isStopTreading = true; | 
|                     m_Socket.Shutdown(SocketShutdown.Both); | 
|                     m_Socket.Close(); | 
|                 } | 
|             } | 
|             catch (Exception e) | 
|             { | 
|                 Debug.Log(e); | 
|             } | 
|         } | 
|   | 
|     } | 
|   | 
|     static byte[] vCmdBytes = new byte[2]; | 
|     /// <summary> | 
|     /// 解析数据包: FFCC+封包长度+封包(封包头+数据)结构体内容 | 
|     /// </summary> | 
|     /// <param name="vBytes"></param> | 
|     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 = encoder.BaseXorSub(vPackBytes); | 
|                 Array.Copy(vPackBytes, 0, vCmdBytes, 0, 2); | 
|                 var cmd = (ushort)((ushort)(vCmdBytes[0] << 8) + vCmdBytes[1]); | 
|                 bool isRegist = false;  // 未注册封包处理 | 
|   | 
|                 // 处理主工程的封包 | 
|                 if (PackageRegedit.Contain(cmd)) | 
|                 { | 
|                     vNetpack = PackageRegedit.TransPack(socketType, cmd, vPackBytes); | 
|                     if (vNetpack != null) | 
|                     { | 
|                         // if (Launch.Instance.EnableNetLog) | 
|                         // { | 
|                         //     Debug.LogFormat("收包:{0}", vNetpack.GetType().Name); | 
|                         // } | 
|                         m_LastPackageTime = DateTime.Now; | 
|                         GameNetSystem.Instance.PushPackage(vNetpack, this.socketType); | 
|                         isRegist = true; | 
|                     } | 
|                 } | 
|   | 
|   | 
|                 vReadIndex += 6 + vBodyLeng; | 
|   | 
|                 // 未注册封包处理 | 
|                 if (!isRegist) | 
|                 { | 
| #if UNITY_EDITOR | 
|                     PackageRegedit.TransPack(socketType, cmd, vPackBytes); | 
| #endif | 
|                 } | 
|             } | 
|         } | 
|         catch (Exception ex) | 
|         { | 
|             Debug.LogErrorFormat("收包异常:{0}", ex); | 
|         } | 
|   | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 发送信息 | 
|     /// </summary> | 
|     public void SendInfo(GameNetPackBasic protocol) | 
|     { | 
|         if (!connected) | 
|         { | 
|             return; | 
|         } | 
|   | 
|         if (protocol == null) | 
|         { | 
|             Debug.LogError("要发的信息对象为空"); | 
|             return; | 
|         } | 
|   | 
|         // if (Launch.Instance.EnableNetLog) | 
|         // { | 
|         //     Debug.LogFormat("发包:{0}", protocol.GetType().Name); | 
|         // } | 
|   | 
|         if (protocol.combineBytes == null) | 
|         { | 
|             protocol.WriteToBytes(); | 
|         } | 
|         protocol.CombineDatas(encoder); | 
| #if UNITY_EDITOR | 
|         NetPkgCtl.RecordPackage(socketType, protocol.vInfoCont, NetPackagetType.Client, protocol.ToString(), FieldPrint.PrintFields(protocol), FieldPrint.PrintFieldsExpand(protocol, true)); | 
| #endif | 
|         sendBytesTotal += protocol.combineBytes.Length; | 
|         SendBytes(protocol.combineBytes); | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 发送信息 | 
|     /// </summary> | 
|     /// <param name="vBytes"></param> | 
|     public void SendInfo(byte[] vBytes) | 
|     { | 
|         if (!connected) | 
|         { | 
|             Debug.LogError("尚未与该后端链接!无法发送信息"); | 
|             return; | 
|         } | 
|   | 
|         if (vBytes == null || vBytes.Length < 2) | 
|         { | 
|             Debug.LogError("要发的信息数据为空或数据不足"); | 
|             return; | 
|         } | 
|   | 
|         vBytes = encoder.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); | 
|     } | 
|   | 
|     Queue<byte[]> sendQueue = new Queue<byte[]>(); | 
|     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 | 
|         { | 
|             Debug.LogError("网络数据包发送异常"); | 
|         } | 
|     } | 
|   | 
|     /// <summary> | 
|     /// 发送完成的回调 | 
|     /// </summary> | 
|     /// <param name="vAsyncSend"></param> | 
|     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) | 
|         { | 
|             Debug.Log(ex); | 
|         } | 
|     } | 
|   | 
| } |