using UnityEngine; using System; using System.IO; using System.Net; using System.Net.Sockets; using System.Collections; using System.Collections.Generic; using GameLogic; using System.Text; using LuaInterface; //using System.Runtime.InteropServices; public enum NetworkStateType { Connected, ConnectFail, Reconnected, ReconnectFail, Exception, Disconnect, } static class IPAddressExtensions { public static IPAddress MapToIPv6(this IPAddress addr) { if (addr.AddressFamily != AddressFamily.InterNetwork) throw new ArgumentException("Must pass an IPv4 address to MapToIPv6"); string ipv4str = addr.ToString(); return IPAddress.Parse("::ffff:" + ipv4str); } public static bool IsIPv4MappedToIPv6(this IPAddress addr) { bool pass1 = addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6, pass2; try { pass2 = (addr.ToString().StartsWith("0000:0000:0000:0000:0000:ffff:") || addr.ToString().StartsWith("0:0:0:0:0:ffff:") || addr.ToString().StartsWith("::ffff:")) && IPAddress.Parse(addr.ToString().Substring(addr.ToString().LastIndexOf(":") + 1)).AddressFamily == AddressFamily.InterNetwork; } catch { return false; } return pass1 && pass2; } } public class SocketClient { public NetworkManager netMgr; private TcpClient client = null; private NetworkStream outStream = null; private MemoryStream _memStream; public MemoryStream CurMemoryStream { get { if (_memStream == null) _memStream = new MemoryStream(); return _memStream; } } private BinaryReader _reader; public BinaryReader CurReader { get { if (_reader == null) _reader = new BinaryReader(_memStream); return _reader; } } static readonly int HeaderSize = sizeof(ushort) + sizeof(int); private const int MAX_READ = 8192; private byte[] byteBuffer = new byte[MAX_READ]; static TEA crypto = new TEA(); Queue mEvents = new Queue(); Stack stateInfoStack = new Stack(); Dictionary dispatchers = new Dictionary(); Dictionary callbacks = new Dictionary(); int m_serialId; int m_indicationSid; bool m_isConnected = false; bool m_isConnecting = false; private const int INDICATION_RESPONSE = 10046; private const int INDICATION_ERROR_CODE = 10400; public string IpAddress { get; private set; } public int Port { get; private set; } // Use this for initialization public SocketClient(string ipAddress, int port) { //Debug.Log("****Socket*********************创建一个Socket ---" + ipAddress); IpAddress = ipAddress; Port = port; _memStream = new MemoryStream(); _reader = new BinaryReader(_memStream); } public void SetIpAddress(string ipAddress, int port) { if (!IsConnected()) { IpAddress = ipAddress; Port = port; m_indicationSid = 0; m_serialId = 1; } } /// /// 连接服务器 /// public void Connect() { //Debug.Log("****Socket*********************Connect ---" + IpAddress); Close(); try { var ipType = GetIPAddressType(IpAddress); client = null; client = new TcpClient(ipType); client.SendTimeout = 1000; client.ReceiveTimeout = 1000; client.NoDelay = true; client.BeginConnect(IpAddress, Port, new AsyncCallback(OnConnect), null); } catch (Exception e) { OnConnectFail(); Debug.LogWarning(e.Message); } } public void OnConnectFail() { //Debug.Log("****Socket*********************OnConnectFail ---" + IpAddress); AddStateInfo(NetworkStateType.ConnectFail, null); } /// /// 连接上服务器 /// void OnConnect(IAsyncResult asr) { //Debug.Log("****Socket*********************OnConnect ---" + IpAddress); //outStream = client.GetStream(); //client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null); //AddStateInfo(NetworkStateType.Connected, null); m_isConnecting = false; //检测是否成功的建立了链接。.. if (client == null || !client.Connected) { Debug.Log("****Socket*********************OnConnect FAILED ---" + IpAddress); return; } try { //完成本次链接 client.EndConnect(asr); // 记录链接的成功事件。 outStream = client.GetStream(); client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null); AddStateInfo(NetworkStateType.Connected, null); Debug.Log("****Socket*********************OnConnect SUCCESS ---" + IpAddress); } catch (Exception e) { Debug.Log("****Socket*********************OnConnect FAILED ---" + e.Message); } } /// /// 写数据 /// void WriteMessage(byte[] message) { MemoryStream ms = null; using (ms = new MemoryStream()) { ms.Position = 0; BinaryWriter writer = new BinaryWriter(ms); short msglen = (short)message.Length; msglen = IPAddress.HostToNetworkOrder(msglen); byte[] tempBuffer = new byte[message.Length]; Buffer.BlockCopy(message, 0, tempBuffer, 0, message.Length); if (crypto != null) tempBuffer = crypto.Encode(tempBuffer); writer.Write(tempBuffer); writer.Flush(); if (client != null && client.Connected) { //NetworkStream stream = client.GetStream(); byte[] payload = ms.ToArray(); outStream.BeginWrite(payload, 0, payload.Length, new AsyncCallback(OnWrite), ms); } else { Debug.Log("client.connected----->>false"); } } } int _NNN; /// /// 读取消息 /// void OnRead(IAsyncResult asr) { int bytesRead = 0; try { //System.Net.Sockets.Socket.SocketAsyncResult //NetBug.Fix by FHF.. //甄别socket当前是否正在连接中,避免重连的间隔内收到服务端消息。. if (client == null || !client.Connected) return; //int ilen = client.GetStream().EndRead(asr); // Debug.Log("[SocketClient] From Socket: EndRead.Len:" + ilen); lock (client.GetStream()) { //读取字节流到缓冲区 bytesRead = client.GetStream().EndRead(asr); } if (bytesRead < 1) { //包尺寸有问题,断线处理 AddStateInfo(NetworkStateType.Disconnect, "bytesRead < 1"); return; } Debug.Log("[SocketClient] NowClient:@" + ++_NNN+" _:"+bytesRead + ":" + client.Client.Handle); OnReceive(byteBuffer, bytesRead); //分析数据包内容,抛给逻辑层 lock (client.GetStream()) { //分析完,再次监听服务器发过来的新消息 Array.Clear(byteBuffer, 0, byteBuffer.Length); //清空数组 client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null); } //Debug.Log("SocketClient.OnRead " + byteBuffer.ToString()); } catch (Exception ex) { Debug.LogError("SocketClient.OnRead " + ex.ToString()); //Lnhbuc_PrintBytes(); AddStateInfo(NetworkStateType.Exception, ex.Message); } } /// /// 丢失链接 /// public void AddStateInfo(NetworkStateType dis, string msg) { NetworkStateInfo info = new NetworkStateInfo(); info.type = dis; info.msg = msg; stateInfoStack.Push(info); } /// /// 打印字节 /// /// void Lnhbuc_PrintBytes() { string returnStr = string.Empty; for (int i = 0; i < byteBuffer.Length; i++) { returnStr += byteBuffer[i].ToString("X2"); } Debug.LogError(returnStr); } /// /// 向链接写入数据流 /// void OnWrite(IAsyncResult r) { try { MemoryStream stream = (MemoryStream)r.AsyncState; outStream.EndWrite(r); if (stream != null) { stream.Close(); } } catch (Exception ex) { Debug.LogError("OnWrite--->>>" + ex.Message); } } /// /// 接收到消息 /// void OnReceive(byte[] bytes, int length) { //Debug.Log("****Socket*********************OnReceive ---" + IpAddress); try { var stream = CurMemoryStream; var reader = CurReader; stream.Seek(0, SeekOrigin.End); stream.Write(bytes, 0, length); //Reset to beginning stream.Seek(0, SeekOrigin.Begin); while (Bkupkw_RemainingBytes() > 4) { short messageLen = reader.ReadInt16(); messageLen = IPAddress.NetworkToHostOrder(messageLen); //memStream.Seek(0, SeekOrigin.Begin); //TEA解密需要补齐8位 int decodeMessageLen = (messageLen + 7) / 8 * 8; if (Bkupkw_RemainingBytes() >= decodeMessageLen) //粘包处理 { var msgBytes = reader.ReadBytes(decodeMessageLen); if (crypto != null) msgBytes = crypto.Decode(msgBytes, messageLen); OnReceivedMessage(new ByteBuffer(msgBytes)); } else { //Back up the position two bytes stream.Position = stream.Position - 2; break; } } //Create a new stream with any leftover bytes byte[] leftover = reader.ReadBytes((int)Bkupkw_RemainingBytes()); stream.SetLength(0); //Clear stream.Write(leftover, 0, leftover.Length); } catch (Exception e) { Debug.LogError("Network Read Exception: " + e.ToString()); AddStateInfo(NetworkStateType.Disconnect, "Network Read Exception: " + e.ToString()); } } /// /// 剩余的字节 /// private long Bkupkw_RemainingBytes() { return CurMemoryStream.Length - CurMemoryStream.Position; } /// /// 接收到消息 /// /// void OnReceivedMessage(ByteBuffer buffer) { //NetBug.Fix by FHF.. //甄别socket当前是否正在连接中,避免重连的间隔内收到服务端消息。. if (client == null || !client.Connected) return; //user id buffer.ReadIntToByte(); //token buffer.ReadIntToByte(); //协议号 int msgid = buffer.ReadIntToByte(); Debug.Log("[SocketClient:OnReceivedMessage]msgid:" + msgid); //收到心跳包 if (msgid == 1001) { lock (mEvents) { mEvents.Enqueue(new NetMsg(msgid, 0, 0, buffer)); } return; } //消息index int sId = buffer.ReadIntToByte(); //结果码 int result = buffer.ReadIntToByte(); lock (mEvents) { mEvents.Enqueue(new NetMsg(msgid, sId, result, buffer)); } } private void Ygqmgx_indicationErrorAction(ByteBuffer buffer) { //Debug.Log("****Socket*********************indicationErrorAction ---" + IpAddress); Util.CallMethod("SocketManager", "ReceiveErrorInfo", this, buffer); } /// /// 关闭链接 /// public void Close() { //确保 关闭Client的链接状态。 UnregistNetMessage(INDICATION_ERROR_CODE, Ygqmgx_indicationErrorAction); if (client != null) { try { client.Client.Disconnect(false); //Debug.Log("****Socket*********************Disconnect() ---" + client.Client.Handle+ "@"+ client.Client.LocalEndPoint.ToString()); } catch { } Debug.Log("****Socket*********************Close ---" + client.Client.Handle); try { client.Close(); client = null; } catch { } } m_isConnected = false; m_isConnecting = false; dispatchers.Clear(); callbacks.Clear(); stateInfoStack.Clear(); if (_memStream != null) { _memStream.Dispose(); _memStream = null; } if (_reader != null) { _reader.Close(); _reader = null; } Array.Clear(byteBuffer, 0, byteBuffer.Length); //lock (mEvents) //{ mEvents.Clear(); //} } bool testConnect; public void Update() { // FHF DEBUG //TimeSpan ts1 = Process.GetCurrentProcess().TotalProcessorTime; //System.Diagnostics.Stopwatch stw = new System.Diagnostics.Stopwatch(); //stw.Start(); if (stateInfoStack.Count > 0) { var info = stateInfoStack.Pop(); if (info.type == NetworkStateType.Connected) { m_isConnected = true; RegistNetMessage(INDICATION_ERROR_CODE, Ygqmgx_indicationErrorAction); Util.CallMethod("SocketManager", "OnConnect", this); } else if (info.type == NetworkStateType.ConnectFail) { Util.CallMethod("SocketManager", "OnConnectFail", this); } else if (info.type == NetworkStateType.Reconnected) { m_isConnected = true; RegistNetMessage(INDICATION_ERROR_CODE, Ygqmgx_indicationErrorAction); Util.CallMethod("SocketManager", "OnReconnect", this); } else if (info.type == NetworkStateType.ReconnectFail) { Util.CallMethod("SocketManager", "OnReconnectFail", this); } else if (info.type == NetworkStateType.Disconnect) { Disconnect(" NetworkStateType.Disconnect"); } else if (info.type == NetworkStateType.Exception) { Disconnect("NetworkStateType.Exception"); } return; } // int _CCC = 0; lock (mEvents) { while (mEvents.Count > 0) { DispatchMessage(mEvents.Dequeue()); // _CCC++; } } testConnect = Input.GetKeyDown(KeyCode.F1); if (testConnect) { UnityEngine.Debug.Log("~~~~~~~~~~~~~测试掉线~~~~~~~~~~~~~~~"); } if (m_isConnecting && !testConnect) { return; } if ((testConnect || !IsConnected()) && m_isConnected) { Disconnect("TEST"); } //FHF Debug time preform // stw.Stop(); // if(_CCC>0) // UnityEngine.Debug.Log("NET EVENT HANDLE: " + _CCC.ToString()+"@"+(stw.ElapsedTicks).ToString()); } void DispatchMessage(NetMsg _event) { int msgId = _event.msgId; ByteBuffer msg = _event.msg; //Debug.LogError("msgId:" + msgId); //Debug.LogError("m_indicationSid:" + m_indicationSid); //Debug.LogError("sid:" + _event.sid); //处理心跳包回调 if (msgId == 1001) { Util.CallMethod("SocketManager", "ReceiveClientHeartBeat", this, msg); return; } //处理错误码 if (_event.result == 0) { m_serialId++; Util.CallMethod("SocketManager", "ReceiveErrorInfo", this, msg); if (callbacks.ContainsKey(msgId)) { callbacks.Remove(msgId); } return; } //处理推送消息,当序列号比本地游标大1,处理推送信息,否则不处理 if (dispatchers.ContainsKey(msgId)) { if (m_indicationSid == _event.sid - 1) { m_indicationSid++; if (!dispatchers[msgId].Process(msg)) { UnityEngine.Debug.LogErrorFormat("Failed to process message. msgId : {0}", msgId); } } if (_event.sid <= m_indicationSid) { //Debug.LogError("INDICATION_RESPONSE" + msgId); m_SendMessage(INDICATION_RESPONSE, null, _event.sid); } } //处理请求回应消息 if (callbacks.ContainsKey(msgId)) { var call = callbacks[msgId]; callbacks.Remove(msgId); m_serialId++; if (!call.Process(msg)) { UnityEngine.Debug.LogErrorFormat("Failed to process message. msgId : {0}", msgId); } } } public string Error; public void Disconnect(string _err) { Error = _err; Debug.Log("****Socket*********************Disconnect [" + Error + "] ---" + IpAddress); Close(); Util.CallMethod("SocketManager", "OnDisconnect", this, _err); } private Coroutine checkConnect_co; IEnumerator CheckConnect_Co() { yield return new WaitForEndOfFrame(); Debug.LogWarning("Start Connecting IP: " + IpAddress + " Port: " + Port); Connect(); m_isConnecting = true; yield return new WaitForSeconds(AppConst.ConnectTimeout); if (!IsConnected()) { OnConnectFail(); } m_isConnecting = false; checkConnect_co = null; } /// /// 发送连接请求 /// public void TryConnect() { //Debug.Log("****Socket*********************TryConnect ---" + IpAddress); if (IsConnected()) { NetworkStateInfo info = new NetworkStateInfo(); info.type = NetworkStateType.Connected; info.msg = null; stateInfoStack.Push(info); return; } if (m_isConnecting) return; if (checkConnect_co != null) { netMgr.StopCoroutine(checkConnect_co); } checkConnect_co = netMgr.StartCoroutine(CheckConnect_Co()); } private Coroutine reconnect_co; IEnumerator CheckReconnect_Co() { m_isConnecting = true; if (IsConnected()) { Close(); yield return new WaitForSeconds(1); } Reconnect(); yield return new WaitForSeconds(AppConst.ConnectTimeout); if (!IsConnected()) { OnReconnectFail(); Close(); } m_isConnecting = false; reconnect_co = null; } float _LastReconectime = 0; public void TryReconnect() { if (IsConnected()) { NetworkStateInfo info = new NetworkStateInfo(); info.type = NetworkStateType.Reconnected; info.msg = null; stateInfoStack.Push(info); return; } if (Time.time - _LastReconectime < AppConst.ConnectTimeout ) return; _LastReconectime = Time.time; Debug.Log("****Socket*********************TryReconnect ---" + IpAddress); if (reconnect_co != null) { netMgr.StopCoroutine(reconnect_co); } reconnect_co = netMgr.StartCoroutine(CheckReconnect_Co()); } public void Reconnect() { Debug.Log("****Socket*********************Reconnect ---" + IpAddress); Close(); try { var ipType = GetIPAddressType(IpAddress); client = null; client = new TcpClient(ipType); Debug.Log("****Socket*********************NEW ---" + client.Client.Handle); //client.SendTimeout = 1000; //client.ReceiveTimeout = 1000; client.NoDelay = true; client.BeginConnect(IpAddress, Port, new AsyncCallback(OnReconnect), null); } catch (Exception e) { Debug.LogError(e.Message); OnReconnectFail(); } } public AddressFamily GetIPAddressType(string ip) { bool hasIpv4 = false; bool hasIpv6 = false; try { IPAddress[] address = Dns.GetHostAddresses(ip); for (int i = 0; i < address.Length; i++) { //从IP地址列表中筛选出IPv4类型的IP地址 //AddressFamily.InterNetwork表示此IP为IPv4, //AddressFamily.InterNetworkV6表示此地址为IPv6类型 if (address[i].AddressFamily == AddressFamily.InterNetwork) { hasIpv4 = true; } else if (address[i].AddressFamily == AddressFamily.InterNetworkV6) { hasIpv6 = true; } Util.Log("Network IPAddresssFamily: " + address[i].AddressFamily.ToString() + " IP: " + address[i].ToString()); } } catch (Exception ex) { Debug.LogWarning("Network GetIPAddressType Exception: " + ex); return AddressFamily.InterNetwork; } if (hasIpv4) return AddressFamily.InterNetwork; if (hasIpv6) return AddressFamily.InterNetworkV6; return AddressFamily.InterNetwork; } public void OnReconnectFail() { Debug.Log("****Socket*********************OnReconnectFail ---" + IpAddress); AddStateInfo(NetworkStateType.ReconnectFail, null); } void OnReconnect(IAsyncResult result) { _LastReconectime = 0; m_isConnecting = false; //检测是否成功的建立了链接。.. if (client == null || !client.Connected) { Debug.Log("****Socket*********************OnReconnect FAILED ---" + IpAddress); return; } try { //完成本次链接 client.EndConnect(result); // 记录链接的成功事件。 outStream = client.GetStream(); client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null); AddStateInfo(NetworkStateType.Reconnected, null); _LastReconectime = 0; Debug.Log("****Socket*********************OnReconnect SUCCESS @"+ client.Client.LocalEndPoint.ToString()); } catch (Exception e) { Debug.Log("****Socket*********************OnReconnect FAILED ---" + e.Message); } } /// /// 发送消息 /// public void SendMessage(int msgId, ByteBuffer msg) { m_serialId++; m_SendMessage(msgId, msg, m_serialId); } void m_SendMessage(int msgId, ByteBuffer msg, int sn) { if (!IsConnected()) { return; } ByteBuffer buffer = new ByteBuffer(); buffer.WriteIntToByte(AppConst.UserId); buffer.WriteIntToByte(AppConst.Token); buffer.WriteIntToByte(msgId); buffer.WriteIntToByte(sn); if (msg != null) { buffer.WriteBuffer(new LuaInterface.LuaByteBuffer(msg.ToBytes())); msg.Close(); } WriteMessage(buffer.ToBytes()); buffer.Close(); Debug.Log("[SocketClient.m_SendMessage]..."+ msgId); } /// /// 发送心跳 /// public void SendHeartBeat() { ByteBuffer buffer = new ByteBuffer(); buffer.WriteIntToByte(AppConst.UserId); buffer.WriteIntToByte(AppConst.Token); buffer.WriteIntToByte(1000); WriteMessage(buffer.ToBytes()); buffer.Close(); } public bool IsConnected() { return client != null && client.Connected; } public void RegistNetMessage(int msgId, Action handle) { if (!dispatchers.ContainsKey(msgId)) dispatchers.Add(msgId, new SimpleDispatcher()); //XDebug.Log.l("++++++++++++++++RegistNetMessage================================", msgId, IpAddress, Port); SimpleDispatcher find = (SimpleDispatcher)dispatchers[msgId]; find.processor += handle; } public void UnregistNetMessage(int msgId, Action handle) { if (!dispatchers.ContainsKey(msgId)) return; dispatchers.Remove(msgId); XDebug.Log.l("-------------------UnregistNetMessage================================", msgId, IpAddress, Port); //SimpleDispatcher find = (SimpleDispatcher)dispatchers[msgId]; //find.processor -= handle; } public void SendMessageWithCallBack(int msgId, int receiveMsgId, ByteBuffer message, LuaFunction callback) { if (!IsConnected()) { UnityEngine.Debug.LogErrorFormat("Try to send message with invalid connection."); AddStateInfo(NetworkStateType.Disconnect, "bytesRead < 1"); } else { SimpleDispatcher cb = new SimpleDispatcher(); cb.processor += b => callback.Call(b); if (!callbacks.ContainsKey(receiveMsgId)) { callbacks.Add(receiveMsgId, cb); } m_SendMessage(msgId, message, m_serialId); } } }