using System; using System.Collections.Generic; using System.Net.Sockets; using System.Text; using UnityEngine; using System.Timers; /// /// socket静态类 /// public static class Network { private static NetworkChild nowSocket = null; //当前socket private static List route = new List(); //路由数组 private static Dictionary> handlers = new Dictionary>(); //路由处理函数 private static List msgCache = new List(); //缓存的消息列表 private static object lockObj = new object(); private static string md5 = ""; // route消息列表的md5 private static string state_open = "state_open"; private static string state_close = "state_close"; /// /// 注册路由 /// /// 路由名称 /// 路由函数 public static void AddHandler(string cmd, Action handler) { handlers[cmd] = handler; } /// /// 移除消息监听 /// /// public static void RemoveThisHandlers(object target) { List dels = new List(); foreach (var one in handlers) { if (one.Value.Target == target) { dels.Add(one.Key); } } foreach (var index in dels) { handlers.Remove(index); } } /// /// socket关闭事件的回调 /// /// 回调函数 public static void OnClose(Action handler) { handlers[state_close] = handler; } /// /// 移除socket关闭事件的回调 /// public static void OffClose() { handlers.Remove(state_close); } /// /// socket打开事件的回调 /// /// 回调函数 public static void OnOpen(Action handler) { handlers[state_open] = handler; } /// /// 移除socket打开事件的回调 /// public static void OffOpen() { handlers.Remove(state_open); } /// /// 断开socket连接 /// public static void DisConnect() { if (nowSocket != null) { nowSocket.DisConnect(); } lock (lockObj) { msgCache.Clear(); } } /// /// 连接服务器 /// /// ip /// 端口 public static void Connect(string host, int port) { DisConnect(); nowSocket = new NetworkChild(); nowSocket.Connect(host, port); } /// /// 发送消息 /// /// 路由名称 /// 数据 public static void SendMsg(string cmd, object data = null) { int cmdIndex = route.IndexOf(cmd); if (cmdIndex == -1) { Debug.Log("cmd not exists: " + cmd); return; } if (nowSocket == null) { Debug.Log("socket is null"); return; } string msg; if (data == null) { msg = "null"; } else { msg = JsonUtility.ToJson(data); } nowSocket.Send(cmdIndex, msg); } /// /// 读取消息 /// public static void ReadMsg() { lock (lockObj) { if (msgCache.Count > 0) { SocketMsg msg = msgCache[0]; msgCache.RemoveAt(0); if (handlers.ContainsKey(msg.msgId)) { handlers[msg.msgId](msg.msg); } } } } private class NetworkChild { private Socket mySocket = null; //原生socket private bool isDead = false; //是否已被弃用 private Timer heartbeatTimer = null; // 心跳 private Timer heartbeatTimeoutTimer = null; // 心跳回应超时 enum ReadType { head, // 头部 some, // 部分关键信息 msg, // 具体消息 } public void DisConnect() { if (!isDead) { nowSocket = null; isDead = true; if (heartbeatTimer != null) { heartbeatTimer.Enabled = false; heartbeatTimer.Dispose(); } if (heartbeatTimeoutTimer != null) { heartbeatTimeoutTimer.Enabled = false; heartbeatTimeoutTimer.Dispose(); } try { mySocket.Shutdown(SocketShutdown.Both); mySocket.Close(); } catch (Exception e) { Debug.Log(e); } } } public void Send(int cmdIndex, string data) { byte[] bytes = Encode(cmdIndex, data); try { mySocket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, null, null); } catch (Exception e) { Debug.Log(e); SocketClose(); } } public void Connect(string host, int port) { try { mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); mySocket.BeginConnect(host, port, AsyncConnectCallback, mySocket); } catch (Exception e) { Debug.Log(e); SocketClose(); } } private void AsyncConnectCallback(IAsyncResult result) { try { // 异步写入结束 mySocket.EndConnect(result); Recive(); // 握手 Proto_Handshake_req msgReq = new Proto_Handshake_req(); msgReq.md5 = md5; byte[] byteMsg = Encoding.UTF8.GetBytes(JsonUtility.ToJson(msgReq)); byte[] byteEnd = new byte[5 + byteMsg.Length]; int msgLen = byteMsg.Length + 1; int index = 0; byteEnd[index++] = (byte)(msgLen >> 24 & 0xff); byteEnd[index++] = (byte)(msgLen >> 16 & 0xff); byteEnd[index++] = (byte)(msgLen >> 8 & 0xff); byteEnd[index++] = (byte)(msgLen & 0xff); byteEnd[index++] = 2 & 0xff; byteMsg.CopyTo(byteEnd, index); mySocket.BeginSend(byteEnd, 0, byteEnd.Length, SocketFlags.None, null, null); } catch (Exception e) { Debug.Log(e); SocketClose(); } } private byte[] Encode(int cmd, string data) { byte[] byteMsg = Encoding.UTF8.GetBytes(data); byte[] byteEnd = new byte[byteMsg.Length + 7]; int len = byteMsg.Length + 3; int index = 0; byteEnd[index++] = (byte)(len >> 24 & 0xff); byteEnd[index++] = (byte)(len >> 16 & 0xff); byteEnd[index++] = (byte)(len >> 8 & 0xff); byteEnd[index++] = (byte)(len & 0xff); byteEnd[index++] = 1; byteEnd[index++] = (byte)(cmd >> 8 & 0xff); byteEnd[index++] = (byte)(cmd & 0xff); byteMsg.CopyTo(byteEnd, index); return byteEnd; } private byte[] data = new byte[2 * 1024]; // socket接收字节流 private ReadType readType = ReadType.head; // 读取消息阶段 private int msgType = 0; // 消息类型 private int byteIndex = 0; // 当前字节流写入到哪个位置了 private byte[] headBytes = new byte[5]; // 头部字节流,固定为5个字节 private byte[] someBytes = new byte[2]; // 部分关键信息字节流,目前只有自定义消息用到,且固定为2个字节 private byte[] msgBytes = new byte[0]; // 具体消息字节流 private void Recive() { try { //开始接收数据 mySocket.BeginReceive(data, 0, data.Length, SocketFlags.None, asyncResult => { int length = mySocket.EndReceive(asyncResult); if (readType == ReadType.head) { ReadHead(0, length); } else if (readType == ReadType.some) { ReadSome(0, length); } else if (readType == ReadType.msg) { ReadMsg(0, length); } Recive(); }, null); } catch (Exception e) { Debug.Log(e); SocketClose(); } } private void ReadHead(int readLen, int length) { readType = ReadType.head; if (readLen >= length) { return; } if (length - readLen < headBytes.Length - byteIndex) // 数据未全部到达 { Array.Copy(data, readLen, headBytes, byteIndex, length - readLen); byteIndex += length - readLen; } else // 数据全到达 { Array.Copy(data, readLen, headBytes, byteIndex, headBytes.Length - byteIndex); readLen += headBytes.Length - byteIndex; int allLen = (headBytes[0] << 24) | (headBytes[1] << 16) | (headBytes[2] << 8) | headBytes[3]; msgType = headBytes[4]; if (msgType == 1) // 自定义消息 { msgBytes = new byte[allLen - 3]; byteIndex = 0; ReadSome(readLen, length); } else { msgBytes = new byte[allLen - 1]; byteIndex = 0; ReadMsg(readLen, length); } } } private void ReadSome(int readLen, int length) { readType = ReadType.some; if (readLen >= length) { return; } if (length - readLen < someBytes.Length - byteIndex) // 数据未全部到达 { Array.Copy(data, readLen, someBytes, byteIndex, length - readLen); byteIndex += length - readLen; } else // 数据全到达 { Array.Copy(data, readLen, someBytes, byteIndex, someBytes.Length - byteIndex); readLen += someBytes.Length - byteIndex; byteIndex = 0; ReadMsg(readLen, length); } } private void ReadMsg(int readLen, int length) { readType = ReadType.msg; if (msgBytes.Length == 0) // 具体消息长度就是0 { HandleMsg(); msgBytes = null; byteIndex = 0; ReadHead(readLen, length); return; } if (readLen >= length) { return; } if (length - readLen < msgBytes.Length - byteIndex) // 数据未全部到达 { Array.Copy(data, readLen, msgBytes, byteIndex, length - readLen); byteIndex += length - readLen; } else // 数据全到达 { Array.Copy(data, readLen, msgBytes, byteIndex, msgBytes.Length - byteIndex); readLen += msgBytes.Length - byteIndex; HandleMsg(); msgBytes = null; byteIndex = 0; ReadHead(readLen, length); } } private void HandleMsg() { if (msgType == 1) // 自定义消息 { int index = (someBytes[0] << 8) | someBytes[1]; if (index < route.Count) { SocketMsg msg = new SocketMsg(); msg.msgId = route[index]; msg.msg = msgBytes; pushMsg(msg); } } else if (msgType == 2) // 握手回调 { string tmpStr = Encoding.UTF8.GetString(msgBytes); Proto_Handshake_rsp handshakeMsg = JsonUtility.FromJson(tmpStr); DealHandshake(handshakeMsg); } else if (msgType == 3) // 心跳回调 { if (heartbeatTimeoutTimer != null) { heartbeatTimeoutTimer.Stop(); } } } private void DealHandshake(Proto_Handshake_rsp msg) { if (msg.heartbeat > 0) { heartbeatTimer = new Timer(); heartbeatTimer.Elapsed += SendHeartbeat; heartbeatTimer.Interval = msg.heartbeat * 1000; heartbeatTimer.Enabled = true; heartbeatTimeoutTimer = new Timer(); heartbeatTimeoutTimer.Elapsed += HeartbeatTimeout; heartbeatTimeoutTimer.AutoReset = false; heartbeatTimeoutTimer.Interval = 4 * 1000; } md5 = msg.md5; if (msg.route != null) { route = new List(); for (int i = 0; i < msg.route.Length; i++) { route.Add(msg.route[i]); } } SocketMsg openMsg = new SocketMsg(); openMsg.msgId = state_open; pushMsg(openMsg); } private void SendHeartbeat(object source, ElapsedEventArgs e) { // 心跳 byte[] bytes = new byte[5]; bytes[0] = 1 >> 24 & 0xff; bytes[1] = 1 >> 16 & 0xff; bytes[2] = 1 >> 8 & 0xff; bytes[3] = 1 & 0xff; bytes[4] = 3 & 0xff; try { mySocket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, null, null); heartbeatTimeoutTimer.Start(); } catch (Exception e1) { Debug.Log(e1); SocketClose(); } } private void HeartbeatTimeout(object source, ElapsedEventArgs e) { SocketClose(); } private void SocketClose() { if (!isDead) { SocketMsg msg = new SocketMsg(); msg.msgId = state_close; pushMsg(msg); DisConnect(); } } private void pushMsg(SocketMsg msg) { lock (lockObj) { msgCache.Add(msg); } } } /// /// 自定义消息 /// private class SocketMsg { public string msgId; public byte[] msg; } /// /// 握手消息 /// [Serializable] private class Proto_Handshake_req { public string md5 = ""; } /// /// 握手消息 /// [Serializable] private class Proto_Handshake_rsp { public float heartbeat = 0; public string md5 = ""; public string[] route = null; } }