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) { IpAddress = ipAddress; Port = port; _memStream = new MemoryStream(); _reader = new BinaryReader(_memStream); Debug.Log("SocketClient SocketClient ipAddress: " + ipAddress + " port: " + port); } public void SetIpAddress(string ipAddress, int port) { Debug.Log("SocketClient SetIpAddress ipAddress: " + ipAddress + " port: " + port); if (!IsConnected()) { IpAddress = ipAddress; Port = port; m_indicationSid = 0; m_serialId = 1; } } /// /// 连接服务器 /// public void Connect() { Close(); Debug.Log("SocketClient Connect ipAddress: " + IpAddress); 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.LogError("SocketClient Connect catch: " + e.Message); } } public void OnConnectFail() { AddStateInfo(NetworkStateType.ConnectFail, "OnConnectFail"); } /// /// 连接上服务器 /// void OnConnect(IAsyncResult asr) { Debug.LogError("SocketClient OnConnect"); outStream = client.GetStream(); client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null); AddStateInfo(NetworkStateType.Connected, "OnConnect"); } /// /// 写数据 /// 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.LogError("SocketClient WriteMessage !connected"); } } } /// /// 读取消息 /// void OnRead(IAsyncResult asr) { int bytesRead = 0; //try { lock (client.GetStream()) { //读取字节流到缓冲区 bytesRead = client.GetStream().EndRead(asr); } if (bytesRead < 1) { //包尺寸有问题,断线处理 AddStateInfo(NetworkStateType.Disconnect, "bytesRead < 1"); return; } OnReceive(byteBuffer, bytesRead); //分析数据包内容,抛给逻辑层 lock (client.GetStream()) { //分析完,再次监听服务器发过来的新消息 Array.Clear(byteBuffer, 0, byteBuffer.Length); //清空数组 client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null); } } //catch (Exception ex) //{ // //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); Debug.Log("SocketClient AddStateInfo dis: " + dis + " msg: " + msg); } /// /// 打印字节 /// /// void PrintBytes() { string returnStr = string.Empty; for (int i = 0; i < byteBuffer.Length; i++) { returnStr += byteBuffer[i].ToString("X2"); } Debug.LogError("SocketClient PrintBytes Str: " + returnStr); } /// /// 向链接写入数据流 /// void OnWrite(IAsyncResult r) { try { MemoryStream stream = (MemoryStream)r.AsyncState; outStream.EndWrite(r); if(stream!=null) { stream.Close(); } } catch (Exception ex) { Debug.LogError("SocketClient OnWrite catch: " + ex.Message.ToString()); } } /// /// 接收到消息 /// void OnReceive(byte[] bytes, int length) { 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 (RemainingBytes() > 4) { short messageLen = reader.ReadInt16(); messageLen = IPAddress.NetworkToHostOrder(messageLen); //memStream.Seek(0, SeekOrigin.Begin); //TEA解密需要补齐8位 int decodeMessageLen = (messageLen + 7) / 8 * 8; if (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)RemainingBytes()); stream.SetLength(0); //Clear stream.Write(leftover, 0, leftover.Length); } catch (Exception e) { Debug.LogError("SocketClient OnReceive catch: " + e.ToString()); AddStateInfo(NetworkStateType.Disconnect, "Network Read Exception: " + e.ToString()); } } /// /// 剩余的字节 /// private long RemainingBytes() { return CurMemoryStream.Length - CurMemoryStream.Position; } /// /// 接收到消息 /// /// void OnReceivedMessage(ByteBuffer buffer) { //user id buffer.ReadIntToByte(); //token buffer.ReadIntToByte(); //协议号 int msgid = buffer.ReadIntToByte(); //收到心跳包 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 indicationErrorAction(ByteBuffer buffer) { Debug.Log("SocketClient indicationErrorAction"); Util.CallMethod("SocketManager", "ReceiveErrorInfo", this, buffer); } /// /// 关闭链接 /// public void Close() { Debug.Log("SocketClient Close"); UnregistNetMessage(INDICATION_ERROR_CODE, indicationErrorAction); m_isConnected = false; m_isConnecting = false; lock (mEvents) { mEvents.Clear(); } dispatchers.Clear(); callbacks.Clear(); stateInfoStack.Clear(); if (client != null) { client.Close(); client = null; } else { Debug.Log("SocketClient Close client==null"); } if (_memStream != null) { _memStream.Dispose(); _memStream = null; } if (_reader != null) { _reader.Close(); _reader = null; } Array.Clear(byteBuffer, 0, byteBuffer.Length); } bool testConnect; public void Update() { if (stateInfoStack.Count > 0) { var info = stateInfoStack.Pop(); if (info.type == NetworkStateType.Connected) { m_isConnected = true; RegistNetMessage(INDICATION_ERROR_CODE, 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, indicationErrorAction); Util.CallMethod("SocketManager", "OnReconnect", this); } else if (info.type == NetworkStateType.ReconnectFail) { Util.CallMethod("SocketManager", "OnReconnectFail", this); } else if (info.type == NetworkStateType.Disconnect) { Disconnect(); } else if (info.type == NetworkStateType.Exception) { Disconnect(); } return; } lock (mEvents) { while (mEvents.Count > 0) { DispatchMessage(mEvents.Dequeue()); } } testConnect = Input.GetKeyDown(KeyCode.F1); if (testConnect) { Debug.Log("~~~~~~~~~~~~~测试掉线~~~~~~~~~~~~~~~"); } if (m_isConnecting && !testConnect) { return; } if ((testConnect || !IsConnected()) && m_isConnected) { Disconnect(); } } void DispatchMessage(NetMsg _event) { int msgId = _event.msgId; ByteBuffer msg = _event.msg; //处理心跳包回调 if (msgId == 1001) { Util.CallMethod("SocketManager", "ReceiveClientHeartBeat", this, msg); return; } //处理错误码 if (_event.result == 0) { Debug.Log("SocketClient DispatchMessage result == 0 msgID: " + msgId + " msg: " + msg); 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)) { Debug.Log("SocketClient DispatchMessage Failed to process message. msgId : " + msgId); } } if (_event.sid <= m_indicationSid) { m_SendMessage(INDICATION_RESPONSE, null, _event.sid); } } //处理请求回应消息 if (callbacks.ContainsKey(msgId)) { var call = callbacks[msgId]; callbacks.Remove(msgId); m_serialId++; if (!call.Process(msg)) { Debug.Log("SocketClient DispatchMessage Failed to process message2. msgId : " + msgId); } } } public void Disconnect() { Debug.Log("SocketClient Disconnect"); Close(); //关掉客户端链接 Util.CallMethod("SocketManager", "OnDisconnect", this); } private Coroutine checkConnect_co; IEnumerator CheckConnect_Co() { yield return new WaitForEndOfFrame(); Debug.Log("SocketClient CheckConnect_Co IP: " + IpAddress + " Port: " + Port); Connect(); m_isConnecting = true; yield return new WaitForSeconds(AppConst.ConnectTimeout); if (!IsConnected()) { Debug.Log("SocketClient CheckConnect_Co connect Fail"); OnConnectFail(); } m_isConnecting = false; checkConnect_co = null; } /// /// 发送连接请求 /// public void TryConnect() { if (IsConnected()) { Debug.Log("SocketClient TryConnect isConnected"); NetworkStateInfo info = new NetworkStateInfo(); info.type = NetworkStateType.Connected; info.msg = null; stateInfoStack.Push(info); return; } if (m_isConnecting) { Debug.Log("SocketClient TryConnect m_isConnecting"); return; } if (checkConnect_co != null) { Debug.Log("SocketClient TryConnect checkConnect_co != nul"); netMgr.StopCoroutine(checkConnect_co); } checkConnect_co = netMgr.StartCoroutine(CheckConnect_Co()); } private Coroutine reconnect_co; IEnumerator CheckReconnect_Co() { Debug.Log("SocketClient TryConnect CheckReconnect_Co"); yield return new WaitForEndOfFrame(); Reconnect(); m_isConnecting = true; yield return new WaitForSeconds(AppConst.ConnectTimeout); if (!IsConnected()) { Debug.Log("SocketClient CheckReconnect_Co connect Fail"); OnReconnectFail(); } m_isConnecting = false; reconnect_co = null; } public void TryReconnect() { if (IsConnected()) { Debug.Log("SocketClient TryReconnect IsConnected"); NetworkStateInfo info = new NetworkStateInfo(); info.type = NetworkStateType.Reconnected; info.msg = null; stateInfoStack.Push(info); return; } if (m_isConnecting) { Debug.Log("SocketClient TryReconnect m_isConnecting"); return; } if (reconnect_co != null) { Debug.Log("SocketClient TryReconnect reconnect_co != nul"); netMgr.StopCoroutine(reconnect_co); } reconnect_co = netMgr.StartCoroutine(CheckReconnect_Co()); } public void Reconnect() { Close(); try { Debug.Log("SocketClient Reconnect"); 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(OnReconnect), null); } catch (Exception e) { Debug.Log("SocketClient Reconnect catch :" + 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.Log("SocketClient GetIPAddressType catch :" + ex.Message); return AddressFamily.InterNetwork; } if (hasIpv4) return AddressFamily.InterNetwork; if (hasIpv6) return AddressFamily.InterNetworkV6; return AddressFamily.InterNetwork; } public void OnReconnectFail() { AddStateInfo(NetworkStateType.ReconnectFail, "OnReconnectFail"); } void OnReconnect(IAsyncResult result) { outStream = client.GetStream(); client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null); AddStateInfo(NetworkStateType.Reconnected, "OnReconnect"); } /// /// 发送消息 /// public void SendMessage(int msgId, ByteBuffer msg) { Debug.Log("SocketClient SendMessage msgID: " + msgId); 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(); } /// /// 发送心跳 /// 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()); SimpleDispatcher find = (SimpleDispatcher)dispatchers[msgId]; find.processor += handle; } public void UnregistNetMessage(int msgId, Action handle) { if (!dispatchers.ContainsKey(msgId)) return; SimpleDispatcher find = (SimpleDispatcher)dispatchers[msgId]; find.processor -= handle; } public void SendMessageWithCallBack(int msgId, int receiveMsgId, ByteBuffer message, LuaFunction callback) { Debug.Log("SocketClient SendMessageWithCallBack msgID:" + msgId.ToString()); 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); } } }