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) 
 | 
            { 
 | 
                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(ipAddress, port); 
 | 
            if (ipEndPoint == null) 
 | 
            { 
 | 
                Debug.Log("IpEndPoint is null"); 
 | 
            } 
 | 
  
 | 
            m_Socket.BeginConnect(ipEndPoint, new AsyncCallback(ConnectCallBack), 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"); 
 | 
        } 
 | 
  
 | 
        m_Socket.BeginConnect(ipEndPoint, new AsyncCallback(ConnectCallBack), null); 
 | 
    } 
 | 
  
 | 
    /// <summary> 
 | 
    /// 链接成功时的回调 
 | 
    /// </summary> 
 | 
    /// <param name="_result"></param> 
 | 
    private void ConnectCallBack(IAsyncResult _result) 
 | 
    { 
 | 
        if (!_result.IsCompleted) 
 | 
        { 
 | 
            DebugEx.Log("链接超时!"); 
 | 
            CloseConnect(); 
 | 
            if (onConnected != null) 
 | 
            { 
 | 
                onConnected(false); 
 | 
                onConnected = null; 
 | 
            } 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
            try 
 | 
            { 
 | 
                if (m_Socket != null && m_Socket.Connected) 
 | 
                { 
 | 
                    DebugEx.Log("确认的链接实现"); 
 | 
                    OnConnectSuccess(); 
 | 
                } 
 | 
                else 
 | 
                { 
 | 
                    if (m_Socket != null) 
 | 
                    { 
 | 
                        m_Socket.Disconnect(true); 
 | 
                    } 
 | 
                } 
 | 
            } 
 | 
            catch (System.Exception ex) 
 | 
            { 
 | 
                DebugEx.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) 
 | 
        { 
 | 
            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; 
 | 
    } 
 | 
  
 | 
    /// <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) 
 | 
            { 
 | 
                DebugEx.Log(e); 
 | 
            } 
 | 
        } 
 | 
  
 | 
    } 
 | 
  
 | 
    static byte[] vCmdBytes = new byte[2]; 
 | 
    /// <summary> 
 | 
    /// 阅读信息 
 | 
    /// </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 (DebugEx.EnableNetLog) 
 | 
                        { 
 | 
                            DebugEx.NetLogFormat("收包:{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) 
 | 
        { 
 | 
            DebugEx.LogError("要发的信息对象为空"); 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        if (DebugEx.EnableNetLog) 
 | 
        { 
 | 
            DebugEx.NetLogFormat("发包:{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) 
 | 
        { 
 | 
            DebugEx.LogError("尚未与该后端链接!无法发送信息"); 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        if (vBytes == null || vBytes.Length < 2) 
 | 
        { 
 | 
            DebugEx.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 
 | 
        { 
 | 
            DebugEx.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) 
 | 
        { 
 | 
            DebugEx.Log(ex); 
 | 
        } 
 | 
    } 
 | 
  
 | 
} 
 |