using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Sockets; using System.Threading; using System.Timers; using UnityEngine; public class SocketInfo { public string IP; public Thread ReceiveThread; public long HeadTime; } /// /// Socket服务端 /// public class SocketServer { /// /// 主线程 /// private readonly SynchronizationContext _mainThread; private const int HEAD_TIMEOUT = 5000; // 心跳超时 毫秒 private const int HEAD_CHECKTIME = 5000; // 心跳包超时检测 毫秒 public readonly Dictionary ClientInfoDic = new Dictionary(); private readonly Socket _server; private System.Timers.Timer _headCheckTimer; private readonly DataBuffer _dataBuffer = new DataBuffer(); public event Action OnConnect; //客户端建立连接回调 public event Action OnDisconnect; // 客户端断开连接回调 public event Action OnReceive; // 接收报文回调 public event Action OnSend; // 发送报文回调 // 目前捕获异常将触发OnDisconnect回调 暂不单独处理 // public event Action OnError; // 异常捕获回调 private bool _isValid = true; public SocketServer(string ip, int port) { OnConnect += (client) => { UnityEngine.Debug.LogFormat("UnityEvo:连接成功 >> IP:{0}", client.LocalEndPoint.ToString()); }; OnDisconnect += (client) => { if(ClientInfoDic.TryGetValue(client, out var value)) Debug.LogFormat("UnityEvo:连接断开 >> IP:{0}", value.IP); }; _mainThread = SynchronizationContext.Current; _server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress ipAddress = IPAddress.Parse(ip); //解析IP地址 _server.Bind(new IPEndPoint(ipAddress, port)); //绑定IP地址:端口 _server.Listen(10); //设定最多10个排队连接请求 // 启动线程监听连接 var connectThread = new Thread(ListenClientConnect); connectThread.Start(); // 心跳包定时检测 _headCheckTimer = new System.Timers.Timer(HEAD_CHECKTIME); _headCheckTimer.AutoReset = true; _headCheckTimer.Elapsed += delegate(object sender, ElapsedEventArgs args) { CheckHeadTimeOut(); }; _headCheckTimer.Start(); Debug.Log($"SocketServer Start: {ip}:{port}"); } /// /// 监听客户端连接 /// private void ListenClientConnect() { while (true) { try { if (!_isValid) break; Socket client = _server.Accept(); IPEndPoint ipEndPoint = (IPEndPoint)client.RemoteEndPoint; Thread receiveThread = new Thread(ReceiveEvent); ClientInfoDic.Add(client, new SocketInfo() { IP = ipEndPoint.Address.ToString(), ReceiveThread = receiveThread, HeadTime = GetNowTime() }); receiveThread.Start(client); PostMainThreadAction(OnConnect, client); } catch { break; } } } /// /// 获取当前时间戳 /// /// private long GetNowTime() { TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalMilliseconds); } public void Send(Socket client, UInt16 e, byte[] buff = null, Action onTrigger = null) { SendMessage(client, e, buff, onTrigger); } private void SendMessage(Socket client, UInt16 e, byte[] buff = null, Action onTrigger = null) { buff = buff ?? new byte[] { }; var dataPack = new SocketDataPack(e, buff); var data = dataPack.Buff; try { client.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback((asyncSend) => { Socket c = (Socket)asyncSend.AsyncState; c.EndSend(asyncSend); PostMainThreadAction(onTrigger, dataPack); PostMainThreadAction(OnSend, client, dataPack); }), client); } catch (SocketException ex) { CloseClient(client); // onError(ex); } } /// /// 线程内接收数据的函数 /// private void ReceiveEvent(object client) { Socket tsocket = (Socket)client; while (true) { if (!_isValid) return; if (!ClientInfoDic.ContainsKey(tsocket)) { return; } try { byte[] rbytes = new byte[8 * 1024]; int len = tsocket.Receive(rbytes); if (len > 0) { _dataBuffer.AddBuffer(rbytes, len); // 将收到的数据添加到缓存器中 if (_dataBuffer.TryUnpack(out var dataPack)) // 尝试解包 { if (dataPack.Type == (UInt16)SocketEvent.ClientHead) { // 接收到心跳包 ReceiveHead(tsocket); } else if (dataPack.Type == (UInt16)SocketEvent.ClientDisconn) { // 客户端断开连接 CloseClient(tsocket); } else if (dataPack.Type == (UInt16)SocketEvent.ClientMessage) { // 收到消息 PostMainThreadAction(OnReceive, tsocket, dataPack); } } } else { if (tsocket.Poll(-1, SelectMode.SelectRead)) { CloseClient(tsocket); return; } } } catch (SocketException ex) { CloseClient(tsocket); // onError(ex); return; } } } /// /// 接收到心跳包 /// private void ReceiveHead(Socket client) { SocketInfo info; if (ClientInfoDic.TryGetValue(client, out info)) { long now = GetNowTime(); long offset = now - info.HeadTime; UnityEngine.Debug.Log("更新心跳时间戳 >>>" + now + " 间隔>>>" + offset); if (offset > HEAD_TIMEOUT) { // 心跳包收到但超时逻辑 } info.HeadTime = now; } } /// /// 检测心跳包超时 /// private void CheckHeadTimeOut() { var tempList = new List(); foreach (var socket in ClientInfoDic.Keys) { tempList.Add(socket); } foreach (var socket in tempList) { var info = ClientInfoDic[socket]; long now = GetNowTime(); long offset = now - info.HeadTime; if (offset > HEAD_TIMEOUT) { // 心跳包超时 KickOut(socket); } } } public void KickOut(Socket client) { // 踢出连接 Send(client, (UInt16)SocketEvent.ServerKickout, null, (dataPack) => { CloseClient(client); }); } public void KickOutAll() { var tempList = new List(); foreach (var socket in ClientInfoDic.Keys) { tempList.Add(socket); } foreach (var socket in tempList) { KickOut(socket); } } /// /// 清理客户端连接 /// /// private void CloseClient(Socket client) { PostMainThreadAction((socket) => { if (OnDisconnect != null) OnDisconnect(socket); ClientInfoDic.Remove(socket); socket.Close(); }, client); } /// /// 关闭 /// public void Close() { if (!_isValid) return; _isValid = false; // if (_connectThread != null) _connectThread.Abort(); var tempList = new List(); foreach (var socket in ClientInfoDic.Keys) { tempList.Add(socket); } foreach (var socket in tempList) { CloseClient(socket); } if (_headCheckTimer != null) { _headCheckTimer.Stop(); _headCheckTimer = null; } _server.Close(); } // /// // /// 错误回调 // /// // /// // private void onError(SocketException ex) // { // PostMainThreadAction(OnError, ex); // } // /// 通知主线程回调 /// private void PostMainThreadAction(Action action) { _mainThread.Post(new SendOrPostCallback((o) => { Action e = (Action)o.GetType().GetProperty("action")?.GetValue(o); if (e != null) e(); }), new { action = action }); } private void PostMainThreadAction(Action action, T arg1) { _mainThread.Post(new SendOrPostCallback((o) => { Action e = (Action)o.GetType().GetProperty("action")?.GetValue(o); T t1 = (T)o.GetType().GetProperty("arg1")?.GetValue(o); if (e != null) e(t1); }), new { action = action, arg1 = arg1 }); } public void PostMainThreadAction(Action action, T1 arg1, T2 arg2) { _mainThread.Post(new SendOrPostCallback((o) => { Action e = (Action)o.GetType().GetProperty("action")?.GetValue(o); T1 t1 = (T1)o.GetType().GetProperty("arg1")?.GetValue(o); T2 t2 = (T2)o.GetType().GetProperty("arg2")?.GetValue(o); if (e != null) e(t1, t2); }), new { action = action, arg1 = arg1, arg2 = arg2 }); } }