This commit is contained in:
sin365 2024-01-15 11:28:29 +08:00
parent b12386d32b
commit 5ab3985f78
3 changed files with 135 additions and 249 deletions

View File

@ -206,24 +206,6 @@ namespace HaoYueNet.ClientNetwork
/// </summary> /// </summary>
public event OnLogOutHandler OnLogOut; public event OnLogOutHandler OnLogOut;
///// <summary>
///// 用于调用者回调的虚函数
///// </summary>
///// <param name="data"></param>
//public virtual void DataCallBack(int CMDID,int ERRCODE,byte[] data)
//{
//}
///// <summary>
///// 断开连接
///// </summary>
///// <param name="sk"></param>
//public virtual void OnClose()
//{
//}
/// <summary> /// <summary>
/// 做好处理的连接管理 /// 做好处理的连接管理
/// </summary> /// </summary>
@ -240,7 +222,6 @@ namespace HaoYueNet.ClientNetwork
OnClose?.Invoke(); OnClose?.Invoke();
} }
/// <summary> /// <summary>
/// 主动关闭连接 /// 主动关闭连接
/// </summary> /// </summary>

View File

@ -1,5 +1,4 @@
using System.Net.Sockets; using System.Net.Sockets;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace HaoYueNet.ServerNetwork namespace HaoYueNet.ServerNetwork
{ {

View File

@ -7,21 +7,11 @@ namespace HaoYueNet.ServerNetwork
{ {
public class TcpSaeaServer public class TcpSaeaServer
{ {
//响应倒计时计数最大值 #region
//public int MaxRevIndexNum { get; set; } = 5; protected int MaxRevIndexNum = 50;//响应倒计时计数最大值
////发送倒计时计数最大值 protected int MaxSendIndexNum = 3;//发送倒计时计数最大值
//public int MaxSendIndexNum { get; set; } = 3; protected static int TimerInterval = 3000;//计时器间隔
protected System.Timers.Timer _heartTimer;//心跳包计数器
//响应倒计时计数最大值
public int MaxRevIndexNum { get; set; } = 50;
//发送倒计时计数最大值
public int MaxSendIndexNum { get; set; } = 3;
//计时器间隔
private static int TimerInterval = 3000;
/// <summary>
/// 心跳包计数器
/// </summary>
private System.Timers.Timer _heartTimer;
public int m_maxConnectNum; //最大连接数 public int m_maxConnectNum; //最大连接数
public int m_revBufferSize; //最大接收字节数 public int m_revBufferSize; //最大接收字节数
protected BufferManager m_bufferManager; protected BufferManager m_bufferManager;
@ -32,10 +22,10 @@ namespace HaoYueNet.ServerNetwork
protected TokenMsgPool msg_pool; protected TokenMsgPool msg_pool;
protected int m_clientCount; //连接的客户端数量 protected int m_clientCount; //连接的客户端数量
protected Semaphore m_maxNumberAcceptedClients;//信号量 protected Semaphore m_maxNumberAcceptedClients;//信号量
List<AsyncUserToken> m_clients; //客户端列表
protected Dictionary<Socket, AsyncUserToken> _DictSocketAsyncUserToken = new Dictionary<Socket, AsyncUserToken>(); protected Dictionary<Socket, AsyncUserToken> _DictSocketAsyncUserToken = new Dictionary<Socket, AsyncUserToken>();
List<AsyncUserToken> m_clients; //客户端列表
public List<AsyncUserToken> ClientList { private set { m_clients = value; } get { return m_clients; } } //获取客户端列表
#endregion
#region #region
/// <summary> /// <summary>
@ -81,13 +71,6 @@ namespace HaoYueNet.ServerNetwork
public event OnNetLogHandler OnNetLog; public event OnNetLogHandler OnNetLog;
#endregion #endregion
#region
/// <summary>
/// 获取客户端列表
/// </summary>
public List<AsyncUserToken> ClientList { get { return m_clients; } }
#endregion
/// <summary> /// <summary>
/// 构造函数 /// 构造函数
/// </summary> /// </summary>
@ -110,7 +93,7 @@ namespace HaoYueNet.ServerNetwork
m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections); m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections);
} }
#region #region Client操
/// <summary> /// <summary>
/// 初始化 /// 初始化
/// </summary> /// </summary>
@ -147,7 +130,6 @@ namespace HaoYueNet.ServerNetwork
} }
OutNetLog("初始化完毕"); OutNetLog("初始化完毕");
} }
/// <summary> /// <summary>
/// 启动服务 /// 启动服务
/// </summary> /// </summary>
@ -188,7 +170,6 @@ namespace HaoYueNet.ServerNetwork
return false; return false;
} }
} }
/// <summary> /// <summary>
/// 停止服务 /// 停止服务
/// </summary> /// </summary>
@ -215,38 +196,42 @@ namespace HaoYueNet.ServerNetwork
if (OnClientNumberChange != null) if (OnClientNumberChange != null)
OnClientNumberChange(-c_count, null); OnClientNumberChange(-c_count, null);
} }
public void CloseClient(AsyncUserToken token) public void CloseClient(AsyncUserToken token)
{ {
try try {token.Socket.Shutdown(SocketShutdown.Both);}
{
token.Socket.Shutdown(SocketShutdown.Both);
}
catch (Exception) { } catch (Exception) { }
} }
/// <summary>
//关闭客户端连接 /// 关闭客户端连接
private void CloseClientSocket(SocketAsyncEventArgs e) /// </summary>
/// <param name="e"></param>
void CloseClientSocket(SocketAsyncEventArgs e)
{ {
AsyncUserToken token = e.UserToken as AsyncUserToken; AsyncUserToken token = e.UserToken as AsyncUserToken;
//调用关闭连接 CloseReady(token);
// 释放SocketAsyncEventArg以便其他客户端可以重用它们
ReleaseSocketAsyncEventArgs(e);
}
void CloseReady(AsyncUserToken token)
{
OnDisconnected?.Invoke(token); OnDisconnected?.Invoke(token);
RemoveUserToken(token); RemoveUserToken(token);
//如果有事件,则调用事件,发送客户端数量变化通知 //如果有事件,则调用事件,发送客户端数量变化通知
OnClientNumberChange?.Invoke(-1, token); OnClientNumberChange?.Invoke(-1, token);
// close the socket associated with the client // 关闭与客户端关联的套接字
try { token.Socket.Shutdown(SocketShutdown.Send); } try { token.Socket.Shutdown(SocketShutdown.Send); } catch (Exception) { }
catch (Exception) { }
token.Socket.Close(); token.Socket.Close();
// decrement the counter keeping track of the total number of clients connected to the server // 递减计数器以跟踪连接到服务器的客户端总数
Interlocked.Decrement(ref m_clientCount); Interlocked.Decrement(ref m_clientCount);
m_maxNumberAcceptedClients.Release(); m_maxNumberAcceptedClients.Release();
// Free the SocketAsyncEventArg so they can be reused by another client
ReleaseSocketAsyncEventArgs(e);
} }
#endregion #endregion
#region Token管理 #region Token管理
public AsyncUserToken GetAsyncUserTokenForSocket(Socket sk)
{
return _DictSocketAsyncUserToken.ContainsKey(sk) ? _DictSocketAsyncUserToken[sk] : null;
}
void AddUserToken(AsyncUserToken userToken) void AddUserToken(AsyncUserToken userToken)
{ {
lock (_DictSocketAsyncUserToken) lock (_DictSocketAsyncUserToken)
@ -271,17 +256,38 @@ namespace HaoYueNet.ServerNetwork
_DictSocketAsyncUserToken.Clear(); _DictSocketAsyncUserToken.Clear();
} }
} }
public AsyncUserToken GetAsyncUserTokenForSocket(Socket sk) /// <summary>
/// 回收SocketAsyncEventArgs
/// </summary>
/// <param name="saea"></param>
/// <exception cref="ArgumentException"></exception>
void ReleaseSocketAsyncEventArgs(SocketAsyncEventArgs saea)
{ {
return _DictSocketAsyncUserToken.ContainsKey(sk) ? _DictSocketAsyncUserToken[sk] : null; //saea.UserToken = null;//TODO
//saea.SetBuffer(null, 0, 0);
//saea.Dispose();
//↑ 这里不要自作主张去清东西,否则回收回去不可用
switch (saea.LastOperation)
{
case SocketAsyncOperation.Receive:
m_Receivepool.Push(saea);
break;
case SocketAsyncOperation.Send:
m_Sendpool.Push(saea);
break;
default:
throw new ArgumentException("ReleaseSocketAsyncEventArgs > The last operation completed on the socket was not a receive or send");
}
} }
#endregion #endregion
#region #region IOCP循环
// Begins an operation to accept a connection request from the client /// <summary>
// /// 开始接受客户端的连接请求的操作
// <param name="acceptEventArg">The context object to use when issuing /// </summary>
// the accept operation on the server's listening socket</param> /// <param name="acceptEventArg">在服务器的侦听套接字上发出接受操作时要使用的上下文对象</param>
public void StartAccept(SocketAsyncEventArgs acceptEventArg) public void StartAccept(SocketAsyncEventArgs acceptEventArg)
{ {
if (acceptEventArg == null) if (acceptEventArg == null)
@ -301,15 +307,15 @@ namespace HaoYueNet.ServerNetwork
ProcessAccept(acceptEventArg); ProcessAccept(acceptEventArg);
} }
} }
/// <summary>
// This method is the callback method associated with Socket.AcceptAsync /// 此方法是与Socket关联的回调方法。AcceptAsync操作并在接受操作完成时调用
// operations and is invoked when an accept operation is complete /// </summary>
// /// <param name="sender"></param>
/// <param name="e"></param>
void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e) void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e)
{ {
ProcessAccept(e); ProcessAccept(e);
} }
private void ProcessAccept(SocketAsyncEventArgs e) private void ProcessAccept(SocketAsyncEventArgs e)
{ {
try try
@ -352,11 +358,12 @@ namespace HaoYueNet.ServerNetwork
} }
#endregion #endregion
#region #region IOCP循环
// This method is invoked when an asynchronous receive operation completes. /// <summary>当异步接收操作完成时,会调用此方法。
// If the remote host closed the connection, then the socket is closed. /// 如果远程主机关闭了连接,则套接字关闭。
// If data was received then the data is echoed back to the client. /// 如果接收到数据,则将数据回显到客户端。
// /// </summary>
/// <param name="e"></param>
private void ProcessReceive(SocketAsyncEventArgs e) private void ProcessReceive(SocketAsyncEventArgs e)
{ {
try try
@ -474,37 +481,30 @@ namespace HaoYueNet.ServerNetwork
default: default:
throw new ArgumentException("The last operation completed on the socket was not a receive or send"); throw new ArgumentException("The last operation completed on the socket was not a receive or send");
} }
} }
#endregion #endregion
/// <summary> #region
/// 回收SocketAsyncEventArgs
/// </summary>
/// <param name="saea"></param>
void ReleaseSocketAsyncEventArgs(SocketAsyncEventArgs saea)
{
//saea.UserToken = null;//TODO
//saea.SetBuffer(null, 0, 0);
//saea.Dispose();
//↑ 这里不要自作主张去清东西,否则回收回去不可用
switch (saea.LastOperation)
{
case SocketAsyncOperation.Receive:
m_Receivepool.Push(saea);
break;
case SocketAsyncOperation.Send:
m_Sendpool.Push(saea);
break;
default:
throw new ArgumentException("ReleaseSocketAsyncEventArgs > The last operation completed on the socket was not a receive or send");
}
}
int sendrun = 0; int sendrun = 0;
private void SendForMsgPool() /// <summary>
/// 对外暴露的发送消息
/// </summary>
/// <param name="CMDID"></param>
/// <param name="data">序列化之后的数据</param>
public void SendToSocket(Socket sk, int CMDID, int ERRCODE, byte[] data)
{
AsyncUserToken token = GetAsyncUserTokenForSocket(sk);
/*HunterNet_S2C _s2cdata = new HunterNet_S2C();
_s2cdata.HunterNetCoreCmdID = CMDID;
_s2cdata.HunterNetCoreData = ByteString.CopyFrom(data);
_s2cdata.HunterNetCoreERRORCode = ERRCODE;
byte[] _finaldata = Serizlize(_s2cdata);*/
//byte[] _finaldata = HunterNet_S2C.CreatePkgData((ushort)CMDID, (ushort)ERRCODE, data);
SendWithIndex(token, (ushort)CMDID, (ushort)ERRCODE, data);
}
void SendForMsgPool()
{ {
//if (flag_SendForMsgPool) return; //if (flag_SendForMsgPool) return;
try try
@ -544,84 +544,12 @@ namespace HaoYueNet.ServerNetwork
} }
} }
/*
public void SendMessage(AsyncUserToken token, byte[] message,bool dontNeedHead = false)
{
if (token == null || token.Socket == null || !token.Socket.Connected)
return;
try
{
if (!dontNeedHead)
{
message = SendDataWithHead(message);
}
if (m_Sendpool.Count > 0) /// <summary>
{ /// 发送心跳包
SocketAsyncEventArgs myreadEventArgs = m_Sendpool.Pop(); /// </summary>
myreadEventArgs.UserToken = token; /// <param name="token"></param>
myreadEventArgs.AcceptSocket = token.Socket; void SendHeartbeatMessage(AsyncUserToken token)
myreadEventArgs.SetBuffer(message, 0, message.Length); //将数据放置进去.
//若不需要等待
if (!token.Socket.SendAsync(myreadEventArgs))
{
m_Sendpool.Push(myreadEventArgs);
}
return;
}
else
{
//先压入队列等待m_Sendpool回收
msg_pool.Enqueue(new TokenWithMsg() { token = token, message = message });
//OutNetLog("压入消息发送队列MSG_Pool");
return;
}
}
catch (Exception e)
{
OutNetLog(e.ToString());
}
}
*/
public void SendMessage(AsyncUserToken token,UInt16 CmdID, UInt16 Error, byte[] data)
{
if (token == null || token.Socket == null || !token.Socket.Connected)
return;
try
{
if (m_Sendpool.Count > 0)
{
SocketAsyncEventArgs myreadEventArgs = m_Sendpool.Pop();
myreadEventArgs.UserToken = token;
myreadEventArgs.AcceptSocket = token.Socket;
//myreadEventArgs.SetBuffer(message, 0, message.Length); //将数据放置进去.
//更换为CMDID和Data直接写入SocketAsyncEventArgs的Buff
HunterNet_S2C.SetDataToSocketAsyncEventArgs(myreadEventArgs, CmdID, Error, data);
//若不需要等待
if (!token.Socket.SendAsync(myreadEventArgs))
{
m_Sendpool.Push(myreadEventArgs);
}
return;
}
else
{
//先压入队列等待m_Sendpool回收
msg_pool.Enqueue(new TokenWithMsg() { token = token, CMDID = CmdID, Error = Error, data = data });
//OutNetLog("压入消息发送队列MSG_Pool");
return;
}
}
catch (Exception e)
{
OutNetLog(e.ToString());
}
}
public void SendHeartbeatMessage(AsyncUserToken token)
{ {
if (token == null || token.Socket == null || !token.Socket.Connected) if (token == null || token.Socket == null || !token.Socket.Connected)
return; return;
@ -656,49 +584,11 @@ namespace HaoYueNet.ServerNetwork
} }
} }
//拼接头部长度
private static byte[] SendDataWithHead(byte[] message)
{
MemoryStream memoryStream = new MemoryStream();//创建一个内存流
byte[] BagHead = BitConverter.GetBytes(message.Length + 4);//往字节数组中写入包头(包头自身的长度和消息体的长度)的长度
memoryStream.Write(BagHead, 0, BagHead.Length);//将包头写入内存流
memoryStream.Write(message, 0, message.Length);//将消息体写入内存流
byte[] HeadAndBody = memoryStream.ToArray();//将内存流中的数据写入字节数组
memoryStream.Close();//关闭内存
memoryStream.Dispose();//释放资源
return HeadAndBody;
}
#region
private void OnCloseReady(AsyncUserToken token)
{
OnDisconnected?.Invoke(token);
RemoveUserToken(token);
//如果有事件,则调用事件,发送客户端数量变化通知
OnClientNumberChange?.Invoke(-1, token);
// close the socket associated with the client
try
{
token.Socket.Shutdown(SocketShutdown.Send);
}
catch (Exception) { }
token.Socket.Close();
// decrement the counter keeping track of the total number of clients connected to the server
Interlocked.Decrement(ref m_clientCount);
m_maxNumberAcceptedClients.Release();
}
/// <summary> /// <summary>
/// 发送数据并计数 /// 发送数据并计数
/// </summary> /// </summary>
/// <param name="data"></param> /// <param name="data"></param>
private void SendWithIndex(AsyncUserToken token, UInt16 CmdID, UInt16 ERRCODE, byte[] data) void SendWithIndex(AsyncUserToken token, UInt16 CmdID, UInt16 ERRCODE, byte[] data)
{ {
try try
{ {
@ -708,29 +598,48 @@ namespace HaoYueNet.ServerNetwork
} }
catch catch
{ {
OnCloseReady(token); CloseReady(token);
} }
} }
/// <summary> void SendMessage(AsyncUserToken token, UInt16 CmdID, UInt16 Error, byte[] data)
/// 对外暴露的发送消息
/// </summary>
/// <param name="CMDID"></param>
/// <param name="data">序列化之后的数据</param>
public void SendToSocket(Socket sk, int CMDID, int ERRCODE, byte[] data)
{ {
AsyncUserToken token = GetAsyncUserTokenForSocket(sk); if (token == null || token.Socket == null || !token.Socket.Connected)
/*HunterNet_S2C _s2cdata = new HunterNet_S2C(); return;
_s2cdata.HunterNetCoreCmdID = CMDID; try
_s2cdata.HunterNetCoreData = ByteString.CopyFrom(data); {
_s2cdata.HunterNetCoreERRORCode = ERRCODE; if (m_Sendpool.Count > 0)
byte[] _finaldata = Serizlize(_s2cdata);*/ {
SocketAsyncEventArgs myreadEventArgs = m_Sendpool.Pop();
myreadEventArgs.UserToken = token;
myreadEventArgs.AcceptSocket = token.Socket;
//myreadEventArgs.SetBuffer(message, 0, message.Length); //将数据放置进去.
//更换为CMDID和Data直接写入SocketAsyncEventArgs的Buff
HunterNet_S2C.SetDataToSocketAsyncEventArgs(myreadEventArgs, CmdID, Error, data);
//byte[] _finaldata = HunterNet_S2C.CreatePkgData((ushort)CMDID, (ushort)ERRCODE, data); //若不需要等待
if (!token.Socket.SendAsync(myreadEventArgs))
SendWithIndex(token, (ushort)CMDID, (ushort)ERRCODE, data); {
m_Sendpool.Push(myreadEventArgs);
} }
return;
}
else
{
//先压入队列等待m_Sendpool回收
msg_pool.Enqueue(new TokenWithMsg() { token = token, CMDID = CmdID, Error = Error, data = data });
//OutNetLog("压入消息发送队列MSG_Pool");
return;
}
}
catch (Exception e)
{
OutNetLog(e.ToString());
}
}
#endregion
#region
private void DataCallBackReady(AsyncUserToken sk, byte[] data) private void DataCallBackReady(AsyncUserToken sk, byte[] data)
{ {
//增加接收计数 //增加接收计数
@ -760,7 +669,6 @@ namespace HaoYueNet.ServerNetwork
} }
} }
} }
private void OutNetLog(string msg) private void OutNetLog(string msg)
{ {
OnNetLog?.Invoke(msg); OnNetLog?.Invoke(msg);
@ -768,7 +676,6 @@ namespace HaoYueNet.ServerNetwork
#endregion #endregion
#region #region
/// <summary> /// <summary>
/// 发送心跳包 /// 发送心跳包
/// </summary> /// </summary>
@ -786,7 +693,7 @@ namespace HaoYueNet.ServerNetwork
} }
catch (Exception e) catch (Exception e)
{ {
OnCloseReady(token); CloseReady(token);
} }
} }
/// <summary> /// <summary>
@ -803,7 +710,7 @@ namespace HaoYueNet.ServerNetwork
if (m_clients[i].RevIndex <= 0) if (m_clients[i].RevIndex <= 0)
{ {
//判定掉线 //判定掉线
OnCloseReady(m_clients[i]); CloseReady(m_clients[i]);
return; return;
} }
@ -818,6 +725,5 @@ namespace HaoYueNet.ServerNetwork
} }
} }
#endregion #endregion
} }
} }