Files
plugin-library/Assets/00.StaryEvo/Runtime/UnitySocket/SocketClient/Scripts/Socket/SocketServer.cs

325 lines
9.9 KiB
C#
Raw Normal View History

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