完善事件代码和整理说明

This commit is contained in:
sin365 2023-07-06 14:47:20 +08:00
parent 2659a11858
commit dcd4166dc3
23 changed files with 306 additions and 260 deletions

Binary file not shown.

View File

@ -13,7 +13,7 @@ namespace HaoYueNet.ClientNetwork
/// <summary> /// <summary>
/// 心跳包数据 /// 心跳包数据
/// </summary> /// </summary>
private byte[] HeartbeatData = new byte[5] { 0x05, 0x00, 0x00, 0x00, 0x00 }; static byte[] HeartbeatData = new byte[5] { 0x05, 0x00, 0x00, 0x00, 0x00 };
////响应倒计时计数最大值 ////响应倒计时计数最大值
//private static int MaxRevIndexNum = 6; //private static int MaxRevIndexNum = 6;
@ -78,13 +78,13 @@ namespace HaoYueNet.ClientNetwork
_heartTimer.Enabled = true; _heartTimer.Enabled = true;
LogOut("开启心跳包检测"); LogOut("开启心跳包检测");
OnConnected(true); OnConnected?.Invoke(true);
return true; return true;
} }
catch (Exception ex) catch (Exception ex)
{ {
LogOut("连接失败:" + ex.ToString()); LogOut("连接失败:" + ex.ToString());
OnConnected(false); OnConnected?.Invoke(false);
return false; return false;
} }
} }
@ -172,24 +172,20 @@ namespace HaoYueNet.ClientNetwork
SendToSocket(_finaldata); SendToSocket(_finaldata);
} }
public delegate void OnDataCallBack_Data(int CMDID, int ERRCODE, byte[] data); #region
public delegate void OnReceiveDataHandler(int CMDID, int ERRCODE, byte[] data);
public event OnDataCallBack_Data OnDataCallBack; public delegate void OnConnectedHandler(bool IsConnected);
public delegate void OnCloseHandler();
public delegate void delegate_NoData(); public delegate void OnLogOutHandler(string Msg);
#endregion
public delegate void delegate_Bool(bool IsConnected);
public event delegate_NoData OnClose;
public event delegate_Bool OnConnected;
public delegate void delegate_str(string Msg);
public event OnConnectedHandler OnConnected;
public event OnReceiveDataHandler OnReceiveData;
public event OnCloseHandler OnClose;
/// <summary> /// <summary>
/// 网络库调试日志输出 /// 网络库调试日志输出
/// </summary> /// </summary>
public event delegate_str OnLogOut; public event OnLogOutHandler OnLogOut;
///// <summary> ///// <summary>
///// 用于调用者回调的虚函数 ///// 用于调用者回调的虚函数
@ -220,7 +216,7 @@ namespace HaoYueNet.ClientNetwork
LogOut("关闭连接"); LogOut("关闭连接");
//关闭Socket连接 //关闭Socket连接
client.Close(); client.Close();
OnClose(); OnClose?.Invoke();
} }
@ -247,7 +243,7 @@ namespace HaoYueNet.ClientNetwork
HunterNet_S2C _c2s = DeSerizlize<HunterNet_S2C>(data); HunterNet_S2C _c2s = DeSerizlize<HunterNet_S2C>(data);
OnDataCallBack(_c2s.HunterNetCoreCmdID, _c2s.HunterNetCoreERRORCode, _c2s.HunterNetCoreData.ToArray()); OnReceiveData(_c2s.HunterNetCoreCmdID, _c2s.HunterNetCoreERRORCode, _c2s.HunterNetCoreData.ToArray());
} }
private void Recive(object o) private void Recive(object o)
@ -356,7 +352,7 @@ namespace HaoYueNet.ClientNetwork
public void LogOut(string Msg) public void LogOut(string Msg)
{ {
//Console.WriteLine(Msg); //Console.WriteLine(Msg);
OnLogOut(Msg); OnLogOut?.Invoke(Msg);
} }
public Socket GetClientSocket() public Socket GetClientSocket()

View File

@ -59,6 +59,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="NetworkHelperCore.cs" /> <Compile Include="NetworkHelperCore.cs" />
<Compile Include="NetworkHelperP2PCore.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ProtobufHunterNetCore.cs" /> <Compile Include="ProtobufHunterNetCore.cs" />
</ItemGroup> </ItemGroup>

View File

@ -16,7 +16,7 @@ namespace HaoYueNet.ClientNetworkNet4x
/// <summary> /// <summary>
/// 心跳包数据 /// 心跳包数据
/// </summary> /// </summary>
private byte[] HeartbeatData = new byte[5] { 0x05, 0x00, 0x00, 0x00, 0x00 }; static byte[] HeartbeatData = new byte[5] { 0x05, 0x00, 0x00, 0x00, 0x00 };
////响应倒计时计数最大值 ////响应倒计时计数最大值
//private static int MaxRevIndexNum = 6; //private static int MaxRevIndexNum = 6;
@ -31,16 +31,16 @@ namespace HaoYueNet.ClientNetworkNet4x
private static int MaxSendIndexNum = 3; private static int MaxSendIndexNum = 3;
//响应倒计时计数 //响应倒计时计数
private static int RevIndex=0; private static int RevIndex = 0;
//发送倒计时计数 //发送倒计时计数
private static int SendIndex=0; private static int SendIndex = 0;
//计时器间隔 //计时器间隔
private static int TimerInterval = 3000; private static int TimerInterval = 3000;
private System.Timers.Timer _heartTimer; private System.Timers.Timer _heartTimer;
public void Init(string IP, int port, bool bBindReuseAddress = false,int bBindport = 0) public void Init(string IP, int port, bool bBindReuseAddress = false, int bBindport = 0)
{ {
LogOut("==>初始化网络核心"); LogOut("==>初始化网络核心");
@ -81,13 +81,13 @@ namespace HaoYueNet.ClientNetworkNet4x
_heartTimer.Enabled = true; _heartTimer.Enabled = true;
LogOut("开启心跳包检测"); LogOut("开启心跳包检测");
OnConnected(true); OnConnected?.Invoke(true);
return true; return true;
} }
catch (Exception ex) catch (Exception ex)
{ {
LogOut("连接失败:" + ex.ToString()); LogOut("连接失败:" + ex.ToString());
OnConnected(false); OnConnected?.Invoke(false);
return false; return false;
} }
} }
@ -165,7 +165,7 @@ namespace HaoYueNet.ClientNetworkNet4x
/// </summary> /// </summary>
/// <param name="CMDID"></param> /// <param name="CMDID"></param>
/// <param name="data">序列化之后的数据</param> /// <param name="data">序列化之后的数据</param>
public void SendToServer(int CMDID,byte[] data) public void SendToServer(int CMDID, byte[] data)
{ {
//LogOut("准备数据 CMDID=> "+CMDID); //LogOut("准备数据 CMDID=> "+CMDID);
HunterNet_C2S _c2sdata = new HunterNet_C2S(); HunterNet_C2S _c2sdata = new HunterNet_C2S();
@ -175,24 +175,20 @@ namespace HaoYueNet.ClientNetworkNet4x
SendToSocket(_finaldata); SendToSocket(_finaldata);
} }
public delegate void OnDataCallBack_Data(int CMDID, int ERRCODE, byte[] data); #region
public delegate void OnReceiveDataHandler(int CMDID, int ERRCODE, byte[] data);
public event OnDataCallBack_Data OnDataCallBack; public delegate void OnConnectedHandler(bool IsConnected);
public delegate void OnCloseHandler();
public delegate void delegate_NoData(); public delegate void OnLogOutHandler(string Msg);
#endregion
public delegate void delegate_Bool(bool IsConnected);
public event delegate_NoData OnClose;
public event delegate_Bool OnConnected;
public delegate void delegate_str(string Msg);
public event OnConnectedHandler OnConnected;
public event OnReceiveDataHandler OnReceiveData;
public event OnCloseHandler OnClose;
/// <summary> /// <summary>
/// 网络库调试日志输出 /// 网络库调试日志输出
/// </summary> /// </summary>
public event delegate_str OnLogOut; public event OnLogOutHandler OnLogOut;
///// <summary> ///// <summary>
///// 用于调用者回调的虚函数 ///// 用于调用者回调的虚函数
@ -223,7 +219,7 @@ namespace HaoYueNet.ClientNetworkNet4x
LogOut("关闭连接"); LogOut("关闭连接");
//关闭Socket连接 //关闭Socket连接
client.Close(); client.Close();
OnClose(); OnClose?.Invoke();
} }
@ -250,7 +246,7 @@ namespace HaoYueNet.ClientNetworkNet4x
HunterNet_S2C _c2s = DeSerizlize<HunterNet_S2C>(data); HunterNet_S2C _c2s = DeSerizlize<HunterNet_S2C>(data);
OnDataCallBack(_c2s.HunterNetCoreCmdID, _c2s.HunterNetCoreERRORCode, _c2s.HunterNetCoreData.ToArray()); OnReceiveData(_c2s.HunterNetCoreCmdID, _c2s.HunterNetCoreERRORCode, _c2s.HunterNetCoreData.ToArray());
} }
private void Recive(object o) private void Recive(object o)
@ -261,7 +257,7 @@ namespace HaoYueNet.ClientNetworkNet4x
while (true) while (true)
{ {
byte[] buffer = new byte[1024 * 1024 * 2]; byte[] buffer = new byte[1024 * 1024 * 2];
int effective=0; int effective = 0;
try try
{ {
effective = client.Receive(buffer); effective = client.Receive(buffer);
@ -270,7 +266,7 @@ namespace HaoYueNet.ClientNetworkNet4x
continue; continue;
} }
} }
catch(Exception ex) catch (Exception ex)
{ {
//远程主机强迫关闭了一个现有的连接 //远程主机强迫关闭了一个现有的连接
OnCloseReady(); OnCloseReady();
@ -312,7 +308,7 @@ namespace HaoYueNet.ClientNetworkNet4x
else else
{ {
//把头去掉,就可以吃了,蛋白质是牛肉的六倍 //把头去掉,就可以吃了,蛋白质是牛肉的六倍
DataCallBackReady(getData.Skip(StartIndex+4).Take(HeadLength-4).ToArray()); DataCallBackReady(getData.Skip(StartIndex + 4).Take(HeadLength - 4).ToArray());
StartIndex += HeadLength;//当读取一条完整的数据后,读取数据的起始下标应为当前接受到的消息体的长度(当前数据的尾部或下一条消息的首部) StartIndex += HeadLength;//当读取一条完整的数据后,读取数据的起始下标应为当前接受到的消息体的长度(当前数据的尾部或下一条消息的首部)
} }
} }
@ -359,7 +355,7 @@ namespace HaoYueNet.ClientNetworkNet4x
public void LogOut(string Msg) public void LogOut(string Msg)
{ {
//Console.WriteLine(Msg); //Console.WriteLine(Msg);
OnLogOut(Msg); OnLogOut?.Invoke(Msg);
} }
public Socket GetClientSocket() public Socket GetClientSocket()

View File

@ -14,13 +14,12 @@ using static Google.Protobuf.Reflection.FieldOptions.Types;
namespace HaoYueNet.ServerNetwork namespace HaoYueNet.ServerNetwork
{ {
public class SocketManager public class TcpSaeaServer
{ {
/// <summary> /// <summary>
/// 心跳包数据 /// 心跳包数据
/// </summary> /// </summary>
private byte[] HeartbeatData = new byte[5] { 0x05, 0x00, 0x00, 0x00, 0x00 }; static byte[] HeartbeatData = new byte[5] { 0x05, 0x00, 0x00, 0x00, 0x00 };
//响应倒计时计数最大值 //响应倒计时计数最大值
//public int MaxRevIndexNum { get; set; } = 5; //public int MaxRevIndexNum { get; set; } = 5;
////发送倒计时计数最大值 ////发送倒计时计数最大值
@ -30,90 +29,69 @@ namespace HaoYueNet.ServerNetwork
public int MaxRevIndexNum { get; set; } = 50; public int MaxRevIndexNum { get; set; } = 50;
//发送倒计时计数最大值 //发送倒计时计数最大值
public int MaxSendIndexNum { get; set; } = 3; public int MaxSendIndexNum { get; set; } = 3;
//计时器间隔 //计时器间隔
private static int TimerInterval = 3000; private static int TimerInterval = 3000;
/// <summary> /// <summary>
/// 心跳包计数器 /// 心跳包计数器
/// </summary> /// </summary>
private System.Timers.Timer _heartTimer; private System.Timers.Timer _heartTimer;
public int m_maxConnectNum; //最大连接数 public int m_maxConnectNum; //最大连接数
public int m_revBufferSize; //最大接收字节数 public int m_revBufferSize; //最大接收字节数
public BufferManager m_bufferManager; protected BufferManager m_bufferManager;
public const int opsToAlloc = 2; protected const int opsToAlloc = 2;
Socket listenSocket; //监听Socket Socket listenSocket; //监听Socket
public SocketEventPool m_Receivepool; protected SocketEventPool m_Receivepool;
protected SocketEventPool m_Sendpool;
public SocketEventPool m_Sendpool; protected TokenMsgPool msg_pool;
public TokenMsgPool msg_pool; protected int m_clientCount; //连接的客户端数量
public int m_clientCount; //连接的客户端数量 protected Semaphore m_maxNumberAcceptedClients;//信号量
public Semaphore m_maxNumberAcceptedClients;//信号量
List<AsyncUserToken> m_clients; //客户端列表 List<AsyncUserToken> m_clients; //客户端列表
public Dictionary<Socket, AsyncUserToken> _DictSocketAsyncUserToken = new Dictionary<Socket, AsyncUserToken>();
protected Dictionary<Socket, AsyncUserToken> _DictSocketAsyncUserToken = new Dictionary<Socket, AsyncUserToken>();
#region Token管理
void ClearUserToken()
{
lock (_DictSocketAsyncUserToken)
{
m_clients.Clear();
_DictSocketAsyncUserToken.Clear();
}
}
void AddUserToken(AsyncUserToken userToken)
{
lock (_DictSocketAsyncUserToken)
{
m_clients.Add(userToken);
_DictSocketAsyncUserToken.Add(userToken.Socket, userToken);
}
}
void RemoveUserToken(AsyncUserToken userToken)
{
lock (_DictSocketAsyncUserToken)
{
m_clients.Remove(userToken);
_DictSocketAsyncUserToken.Remove(userToken.Socket);
}
}
#endregion
#region #region
/// <summary> /// <summary>
/// 客户端连接数量变化时触发 /// 客户端连接数量变化时触发
/// </summary> /// </summary>
/// <param name="num">当前增加客户的个数(用户退出时为负数,增加时为正数,一般为1)</param> /// <param name="num">当前增加客户的个数(用户退出时为负数,增加时为正数,一般为1)</param>
/// <param name="token">增加用户的信息</param> /// <param name="token">增加用户的信息</param>
public delegate void OnClientNumberChange(int num, AsyncUserToken token); public delegate void OnClientNumberChangeHandler(int num, AsyncUserToken token);
/// <summary> /// <summary>
/// 接收到客户端的数据 /// 接收到客户端的数据
/// </summary> /// </summary>
/// <param name="token">客户端</param> /// <param name="token">客户端</param>
/// <param name="buff">客户端数据</param> /// <param name="buff">客户端数据</param>
public delegate void OnReceiveData(AsyncUserToken token, byte[] buff); public delegate void OnReceiveDataHandler(AsyncUserToken sk, int CMDID, byte[] data);
/// <summary>
/// 断开连接
/// </summary>
/// <param name="sk"></param>
public delegate void OnDisconnectHandler(AsyncUserToken sk);
/// <summary>
/// 日志
/// </summary>
/// <param name="sk"></param>
public delegate void OnNetLogHandler(string msg);
#endregion #endregion
#region #region
/// <summary> /// <summary>
/// 客户端连接数量变化事件 /// 客户端连接数量变化事件
/// </summary> /// </summary>
public event OnClientNumberChange ClientNumberChange; public event OnClientNumberChangeHandler OnClientNumberChange;
/// <summary> /// <summary>
/// 接收到客户端的数据事件 /// 接收到客户端的数据事件
/// </summary> /// </summary>
public event OnReceiveData ReceiveClientData; public event OnReceiveDataHandler OnReceive;
/// <summary>
/// 接收到客户端的断开连接
/// </summary>
public event OnDisconnectHandler OnDisconnected;
/// <summary>
/// 网络库内部输出
/// </summary>
public event OnNetLogHandler OnNetLog;
#endregion #endregion
#region #region
@ -128,7 +106,7 @@ namespace HaoYueNet.ServerNetwork
/// </summary> /// </summary>
/// <param name="numConnections">最大连接数</param> /// <param name="numConnections">最大连接数</param>
/// <param name="receiveBufferSize">缓存区大小</param> /// <param name="receiveBufferSize">缓存区大小</param>
public SocketManager(int numConnections, int receiveBufferSize) public TcpSaeaServer(int numConnections, int receiveBufferSize)
{ {
m_clientCount = 0; m_clientCount = 0;
m_maxConnectNum = numConnections; m_maxConnectNum = numConnections;
@ -145,6 +123,7 @@ namespace HaoYueNet.ServerNetwork
m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections); m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections);
} }
#region
/// <summary> /// <summary>
/// 初始化 /// 初始化
/// </summary> /// </summary>
@ -179,16 +158,16 @@ namespace HaoYueNet.ServerNetwork
m_Sendpool.Push(readWriteEventArg); m_Sendpool.Push(readWriteEventArg);
} }
OutNetLog("初始化完毕");
} }
/// <summary> /// <summary>
/// 启动服务 /// 启动服务
/// </summary> /// </summary>
/// <param name="localEndPoint"></param> /// <param name="localEndPoint"></param>
/// <param name="bReuseAddress">是否端口重用</param> /// <param name="bReuseAddress">是否端口重用</param>
/// <returns></returns> /// <returns></returns>
public bool Start(IPEndPoint localEndPoint,bool bReuseAddress = false) public bool Start(IPEndPoint localEndPoint, bool bReuseAddress = false)
{ {
try try
{ {
@ -206,12 +185,14 @@ namespace HaoYueNet.ServerNetwork
// post accepts on the listening socket // post accepts on the listening socket
StartAccept(null); StartAccept(null);
OutNetLog("监听:" + listenSocket.AddressFamily.ToString());
_heartTimer = new System.Timers.Timer(); _heartTimer = new System.Timers.Timer();
_heartTimer.Interval = TimerInterval; _heartTimer.Interval = TimerInterval;
_heartTimer.Elapsed += CheckUpdatetimer_Elapsed; _heartTimer.Elapsed += CheckUpdatetimer_Elapsed;
_heartTimer.AutoReset = true; _heartTimer.AutoReset = true;
_heartTimer.Enabled = true; _heartTimer.Enabled = true;
//Console.WriteLine("开启心跳包定时器"); OutNetLog("开启定时心跳包");
return true; return true;
} }
@ -244,11 +225,10 @@ namespace HaoYueNet.ServerNetwork
int c_count = m_clients.Count; int c_count = m_clients.Count;
ClearUserToken(); ClearUserToken();
if (ClientNumberChange != null) if (OnClientNumberChange != null)
ClientNumberChange(-c_count, null); OnClientNumberChange(-c_count, null);
} }
public void CloseClient(AsyncUserToken token) public void CloseClient(AsyncUserToken token)
{ {
try try
@ -258,7 +238,66 @@ namespace HaoYueNet.ServerNetwork
catch (Exception) { } catch (Exception) { }
} }
//关闭客户端连接
private void CloseClientSocket(SocketAsyncEventArgs e)
{
AsyncUserToken token = e.UserToken as AsyncUserToken;
//调用关闭连接
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();
// Free the SocketAsyncEventArg so they can be reused by another client
ReleaseSocketAsyncEventArgs(e);
}
#endregion
#region Token管理
void AddUserToken(AsyncUserToken userToken)
{
lock (_DictSocketAsyncUserToken)
{
m_clients.Add(userToken);
_DictSocketAsyncUserToken.Add(userToken.Socket, userToken);
}
}
void RemoveUserToken(AsyncUserToken userToken)
{
lock (_DictSocketAsyncUserToken)
{
m_clients.Remove(userToken);
_DictSocketAsyncUserToken.Remove(userToken.Socket);
}
}
void ClearUserToken()
{
lock (_DictSocketAsyncUserToken)
{
m_clients.Clear();
_DictSocketAsyncUserToken.Clear();
}
}
public AsyncUserToken GetAsyncUserTokenForSocket(Socket sk)
{
return _DictSocketAsyncUserToken.ContainsKey(sk) ? _DictSocketAsyncUserToken[sk] : null;
}
#endregion
#region
// Begins an operation to accept a connection request from the client // Begins an operation to accept a connection request from the client
// //
// <param name="acceptEventArg">The context object to use when issuing // <param name="acceptEventArg">The context object to use when issuing
@ -311,7 +350,7 @@ namespace HaoYueNet.ServerNetwork
AddUserToken(userToken); AddUserToken(userToken);
ClientNumberChange?.Invoke(1, userToken); OnClientNumberChange?.Invoke(1, userToken);
if (!e.AcceptSocket.ReceiveAsync(readEventArgs)) if (!e.AcceptSocket.ReceiveAsync(readEventArgs))
{ {
ProcessReceive(readEventArgs); ProcessReceive(readEventArgs);
@ -326,25 +365,9 @@ namespace HaoYueNet.ServerNetwork
if (e.SocketError == SocketError.OperationAborted) return; if (e.SocketError == SocketError.OperationAborted) return;
StartAccept(e); StartAccept(e);
} }
#endregion
void IO_Completed(object sender, SocketAsyncEventArgs e) #region
{
// determine which type of operation just completed and call the associated handler
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
ProcessReceive(e);
break;
case SocketAsyncOperation.Send:
ProcessSend(e);
break;
default:
throw new ArgumentException("The last operation completed on the socket was not a receive or send");
}
}
// This method is invoked when an asynchronous receive operation completes. // This method is invoked when an asynchronous receive operation completes.
// If the remote host closed the connection, then the socket is closed. // 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. // If data was received then the data is echoed back to the client.
@ -364,15 +387,8 @@ namespace HaoYueNet.ServerNetwork
{ {
token.Buffer.AddRange(data); token.Buffer.AddRange(data);
} }
//注意:你一定会问,这里为什么要用do-while循环?
//如果当客户发送大数据流的时候,e.BytesTransferred的大小就会比客户端发送过来的要小,
//需要分多次接收.所以收到包的时候,先判断包头的大小.够一个完整的包再处理.
//如果客户短时间内发送多个小数据包时, 服务器可能会一次性把他们全收了.
//这样如果没有一个循环来控制,那么只会处理第一个包,
//剩下的包全部留在token.Buffer中了,只有等下一个数据包过来后,才会放出一个来.
do do
{ {
//如果包头不完整 //如果包头不完整
if (token.Buffer.Count < 4) if (token.Buffer.Count < 4)
break; break;
@ -392,9 +408,6 @@ namespace HaoYueNet.ServerNetwork
{ {
token.Buffer.RemoveRange(0, packageLen + 4); token.Buffer.RemoveRange(0, packageLen + 4);
} }
//将数据包交给后台处理,这里你也可以新开个线程来处理.加快速度.
if (ReceiveClientData != null)
ReceiveClientData(token, rev);
DataCallBackReady(token, rev); DataCallBackReady(token, rev);
@ -418,7 +431,6 @@ namespace HaoYueNet.ServerNetwork
//RuncomLib.Log.LogUtils.Info(xe.Message + "\r\n" + xe.StackTrace); //RuncomLib.Log.LogUtils.Info(xe.Message + "\r\n" + xe.StackTrace);
} }
} }
private void ProcessSend(SocketAsyncEventArgs e) private void ProcessSend(SocketAsyncEventArgs e)
{ {
if (e.SocketError == SocketError.Success) if (e.SocketError == SocketError.Success)
@ -433,34 +445,29 @@ namespace HaoYueNet.ServerNetwork
ReleaseSocketAsyncEventArgs(e); ReleaseSocketAsyncEventArgs(e);
SendForMsgPool(); SendForMsgPool();
} }
void IO_Completed(object sender, SocketAsyncEventArgs e)
//关闭客户端
private void CloseClientSocket(SocketAsyncEventArgs e)
{ {
AsyncUserToken token = e.UserToken as AsyncUserToken; // determine which type of operation just completed and call the associated handler
//调用关闭连接 switch (e.LastOperation)
OnClose(token);
RemoveUserToken(token);
//如果有事件,则调用事件,发送客户端数量变化通知
if (ClientNumberChange != null)
ClientNumberChange(-1, token);
// close the socket associated with the client
try
{ {
token.Socket.Shutdown(SocketShutdown.Send); case SocketAsyncOperation.Receive:
} ProcessReceive(e);
catch (Exception) { } break;
token.Socket.Close(); case SocketAsyncOperation.Send:
// decrement the counter keeping track of the total number of clients connected to the server ProcessSend(e);
Interlocked.Decrement(ref m_clientCount); break;
m_maxNumberAcceptedClients.Release(); default:
// Free the SocketAsyncEventArg so they can be reused by another client throw new ArgumentException("The last operation completed on the socket was not a receive or send");
ReleaseSocketAsyncEventArgs(e);
} }
}
#endregion
/// <summary>
/// 回收SocketAsyncEventArgs
/// </summary>
/// <param name="saea"></param>
void ReleaseSocketAsyncEventArgs(SocketAsyncEventArgs saea) void ReleaseSocketAsyncEventArgs(SocketAsyncEventArgs saea)
{ {
saea.UserToken = null;//TODO saea.UserToken = null;//TODO
@ -477,7 +484,7 @@ namespace HaoYueNet.ServerNetwork
} }
int sendrun = 0; int sendrun = 0;
public void SendForMsgPool() private void SendForMsgPool()
{ {
//if (flag_SendForMsgPool) return; //if (flag_SendForMsgPool) return;
try try
@ -491,21 +498,21 @@ namespace HaoYueNet.ServerNetwork
try try
{ {
TokenWithMsg msg = msg_pool.Dequeue(); TokenWithMsg msg = msg_pool.Dequeue();
//Console.WriteLine("从信息池取出发送"); //OutNetLog("从信息池取出发送");
SendMessage(msg.token, msg.message); SendMessage(msg.token, msg.message);
msg = null; msg = null;
} }
catch catch
{ {
Console.WriteLine("==============================================>"); OutNetLog("==============================================>");
} }
} }
sendrun--; sendrun--;
Console.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!"); OutNetLog("!!!!!!!!!!!!!!!!!!!!!!!!!!");
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine(ex.ToString()); OutNetLog(ex.ToString());
} }
} }
@ -539,13 +546,13 @@ namespace HaoYueNet.ServerNetwork
{ {
//先压入队列等待m_Sendpool回收 //先压入队列等待m_Sendpool回收
msg_pool.Enqueue(new TokenWithMsg() { token = token, message = message }); msg_pool.Enqueue(new TokenWithMsg() { token = token, message = message });
//Console.WriteLine("压入消息发送队列MSG_Pool"); //OutNetLog("压入消息发送队列MSG_Pool");
return; return;
} }
} }
catch (Exception e) catch (Exception e)
{ {
Console.WriteLine(e.ToString()); OutNetLog(e.ToString());
} }
} }
@ -570,33 +577,15 @@ namespace HaoYueNet.ServerNetwork
} }
#region #region
private void OnCloseReady(AsyncUserToken token)
/// <summary>
/// 用于调用者回调的虚函数
/// </summary>
/// <param name="data"></param>
public virtual void DataCallBack(AsyncUserToken sk, int CMDID, byte[] data)
{ {
OnDisconnected?.Invoke(token);
}
/// <summary>
/// 断开连接
/// </summary>
/// <param name="sk"></param>
public virtual void OnClose(AsyncUserToken sk)
{
}
public virtual void OnCloseReady(AsyncUserToken token)
{
OnClose(token);
RemoveUserToken(token); RemoveUserToken(token);
//如果有事件,则调用事件,发送客户端数量变化通知 //如果有事件,则调用事件,发送客户端数量变化通知
if (ClientNumberChange != null) OnClientNumberChange?.Invoke(-1, token);
ClientNumberChange(-1, token);
// close the socket associated with the client // close the socket associated with the client
try try
{ {
@ -619,7 +608,6 @@ namespace HaoYueNet.ServerNetwork
{ {
//发送数据 //发送数据
SendMessage(token, data); SendMessage(token, data);
token.SendIndex = MaxSendIndexNum; token.SendIndex = MaxSendIndexNum;
} }
catch catch
@ -628,11 +616,6 @@ namespace HaoYueNet.ServerNetwork
} }
} }
public AsyncUserToken GetAsyncUserTokenForSocket(Socket sk)
{
return _DictSocketAsyncUserToken.ContainsKey(sk) ? _DictSocketAsyncUserToken[sk] : null;
}
/// <summary> /// <summary>
/// 对外暴露的发送消息 /// 对外暴露的发送消息
/// </summary> /// </summary>
@ -649,6 +632,40 @@ namespace HaoYueNet.ServerNetwork
SendWithIndex(token, _finaldata); SendWithIndex(token, _finaldata);
} }
private void DataCallBackReady(AsyncUserToken sk, byte[] data)
{
//增加接收计数
sk.RevIndex = MaxRevIndexNum;
if (data.Length == 1 && data[0] == 0x00)//心跳包
{
//OutNetLog("收到心跳包");
//无处理
}
else
{
try
{
HunterNet_C2S _s2c = DeSerizlize<HunterNet_C2S>(data);
//将数据包交给后台处理,这里你也可以新开个线程来处理.加快速度.
OnReceive?.Invoke(sk, (int)_s2c.HunterNetCoreCmdID, _s2c.HunterNetCoreData.ToArray());
//DataCallBack(sk, (int)_s2c.HunterNetCoreCmdID, _s2c.HunterNetCoreData.ToArray());
}
catch (Exception ex)
{
OutNetLog("数据解析错误");
}
}
}
private void OutNetLog(string msg)
{
OnNetLog?.Invoke(msg);
}
#endregion
#region
/// <summary> /// <summary>
/// 发送心跳包 /// 发送心跳包
/// </summary> /// </summary>
@ -660,7 +677,7 @@ namespace HaoYueNet.ServerNetwork
return; return;
try try
{ {
//Console.WriteLine(DateTime.Now.ToString() + "发送心跳包"); //OutNetLog(DateTime.Now.ToString() + "发送心跳包");
token.SendIndex = MaxSendIndexNum; token.SendIndex = MaxSendIndexNum;
SendMessage(token, HeartbeatData, true); SendMessage(token, HeartbeatData, true);
} }
@ -669,31 +686,6 @@ namespace HaoYueNet.ServerNetwork
OnCloseReady(token); OnCloseReady(token);
} }
} }
private void DataCallBackReady(AsyncUserToken sk, byte[] data)
{
//增加接收计数
sk.RevIndex = MaxRevIndexNum;
if (data.Length == 1 && data[0] == 0x00)//心跳包
{
//Console.WriteLine("收到心跳包");
//无处理
}
else
{
try
{
HunterNet_C2S _s2c = DeSerizlize<HunterNet_C2S>(data);
DataCallBack(sk, (int)_s2c.HunterNetCoreCmdID, _s2c.HunterNetCoreData.ToArray());
}
catch (Exception ex)
{
Console.WriteLine("数据解析错误");
}
}
}
/// <summary> /// <summary>
/// 心跳包时钟事件 /// 心跳包时钟事件
/// </summary> /// </summary>

View File

@ -1,26 +1,88 @@
# HaoYueNet # HaoYueNet
.Net 7 的自建基于IOCP的TCP的高性能网络库 .Net 7 的自建基于IOCP的TCP的高性能网络库
使用Protobuff作为通讯协议 使用Protobuff作为基础协议
包含服务端和客户端双端库,可直接用于各类.Net程序或Unity程序做TCP通讯底层库。 包含服务端和客户端双端库,可直接用于各类.Net程序或Unity程序做TCP通讯底层库。
不用关心网络底层,直接引用或继承,即可便捷使用。
DataCallBack//网络消息事件
OnClose//连接关闭
并包含心跳包等检测、连接管理、Protobuff解析优化后的高性能收发等等。 并包含心跳包等检测、连接管理、Protobuff解析优化后的高性能收发等等。
Simple目录下有实例客户端和实例服务端 不用关心网络底层,直接引用或继承,即可便捷使用。
#使用基础事件回调即可:
OnClientNumberChange//连接数发生变化
OnDisconnected//断开连接
OnNetLog//来自网络库的日志信息
OnReceive//收到网络数据
#Simple目录下,有实例客户端和实例服务端
示例中,使用本网络库,您可以继续示例项目写,也可以参照示例代码。 示例中,使用本网络库,您可以继续示例项目写,也可以参照示例代码。
示例中实现了:
实现了:
事件机制, 事件机制,
客户端基本框架(连接管理,数据管理,消息收发,指定用户发送) 客户端基本框架(连接管理,数据管理,消息收发,指定用户发送)
服务端基本框架(连接管理,用户管理,消息收发,指定用户发送,广播等) 服务端基本框架(连接管理,用户管理,消息收发,指定用户发送,广播等)
简单无OAuth登录 简单无OAuth登录
用户列表, 用户列表,
基础的Protobuff设计 基础的Protobuff设计
基础聊天功能, 基础聊天功能,
整合Protobuff生成。 整合Protobuff生成。
您甚至可以 #最简接入示例(服务端和客户端)
若您的应用相对简单您甚至可以基于Simple增加功能快速达成目标.
Server:
```
TcpSaeaServer Srv = new TcpSaeaServer(1024, 1024);//实例化,最大连接数和最大接收字节数
Srv.OnClientNumberChange += (int num, AsyncUserToken client) => { /* 连接数发生变化*/};
Srv.OnDisconnected += (AsyncUserToken client) => { /* 断开连接 */};
Srv.OnNetLog += (string msg) => { /* 来自网络库的日志信息 */};
Srv.OnReceive += (AsyncUserToken client, int CMDID, byte[] data) => {
/* 收到网络消息 CMDID和数据 */
Srv.SendMessage(client, new byte[1] { 0x00 });//给指定连接发送数据
};
Srv.Init();//初始化
Srv.Start(new IPEndPoint(IPAddress.Any.Address, 6000));//启动
```
Client:
```
NetworkHelperCore network = new NetworkHelperCore();
network.OnClose += ()=> { /* 断开连接 */};
network.OnConnected += (bool IsConnect) => { /* 连接回到,成功或失败 */};
network.OnLogOut += (string msg) => { /* 来自网络库的日志信息 */};
//指定接收服务器数据事件
network.OnReceiveData += (int CMDID, int ERRCODE, byte[] data) => {
/* 收到网络消息 CMDID和数据 */
network.SendToServer(CMDID, new byte[1] { 0x00 });//给服务器发送数据
};
network.Init("127.0.0.1", 6000);//连接服务器
```
#引用姿势
方式1.直接解决方案引用项目
方式2.直接引用dll文件
服务端
HaoYueNet.ServerNetwork.dll
客户端
HaoYueNet.ClientNetwork.dll (.net7 推荐跨平台.net程序使用)
HaoYueNet.ClientNetworkNet4x.dll (传统.Net4.X版本,用于传统.NetFX程序或Unity游戏或Mono程序)

View File

@ -16,15 +16,14 @@ namespace ClientCore.Network
public NetworkHelper() public NetworkHelper()
{ {
//指定接收服务器数据事件 //指定接收服务器数据事件
OnDataCallBack += GetDataCallBack; OnReceiveData += GetDataCallBack;
//断开连接 //断开连接
OnClose += OnConnectClose; OnClose += OnConnectClose;
//网络库调试信息输出事件,用于打印连接断开,收发事件
OnLogOut += NetworkDeBugLog;
OnConnected += NetworkConnected; OnConnected += NetworkConnected;
//网络库调试信息输出事件,用于打印网络内容
OnLogOut += NetworkDeBugLog;
} }
public void NetworkConnected(bool IsConnect) public void NetworkConnected(bool IsConnect)
{ {
if (IsConnect) if (IsConnect)

View File

@ -20,7 +20,6 @@ namespace ServerCore.Manager
g_SocketMgr = new IOCPNetWork(1024, 1024); g_SocketMgr = new IOCPNetWork(1024, 1024);
g_SocketMgr.Init(); g_SocketMgr.Init();
g_SocketMgr.Start(new IPEndPoint(IPAddress.Any.Address, port)); g_SocketMgr.Start(new IPEndPoint(IPAddress.Any.Address, port));
Console.WriteLine("监听:" + port);
Console.WriteLine("Succeed!"); Console.WriteLine("Succeed!");
} }
} }

View File

@ -1,19 +1,23 @@
using AxibugProtobuf; using AxibugProtobuf;
using HaoYueNet.ServerNetwork; using HaoYueNet.ServerNetwork;
using ServerCore.Manager; using ServerCore.Manager;
using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
namespace ServerCore.NetWork namespace ServerCore.NetWork
{ {
public class IOCPNetWork : SocketManager public class IOCPNetWork : TcpSaeaServer
{ {
public IOCPNetWork(int numConnections, int receiveBufferSize) public IOCPNetWork(int numConnections, int receiveBufferSize)
: base(numConnections, receiveBufferSize) : base(numConnections, receiveBufferSize)
{ {
ClientNumberChange += IOCPNetWork_ClientNumberChange; OnClientNumberChange += ClientNumberChange;
OnReceive += ReceiveData;
OnDisconnected += OnDisconnect;
OnNetLog += OnShowNetLog;
} }
private void IOCPNetWork_ClientNumberChange(int num, AsyncUserToken token) private void ClientNumberChange(int num, AsyncUserToken token)
{ {
Console.WriteLine("Client数发生变化"); Console.WriteLine("Client数发生变化");
} }
@ -24,12 +28,12 @@ namespace ServerCore.NetWork
/// <param name="CMDID">协议ID</param> /// <param name="CMDID">协议ID</param>
/// <param name="ERRCODE">错误编号</param> /// <param name="ERRCODE">错误编号</param>
/// <param name="data">业务数据</param> /// <param name="data">业务数据</param>
public override void DataCallBack(AsyncUserToken token, int CMDID, byte[] data) private void ReceiveData(AsyncUserToken token, int CMDID, byte[] data)
{ {
DataCallBackToOld(token.Socket, CMDID, data); DataCallBack(token.Socket, CMDID, data);
} }
public void DataCallBackToOld(Socket sk, int CMDID, byte[] data) public void DataCallBack(Socket sk, int CMDID, byte[] data)
{ {
ServerManager.g_Log.Debug("收到消息 CMDID =>" + CMDID + " 数据长度=>" + data.Length); ServerManager.g_Log.Debug("收到消息 CMDID =>" + CMDID + " 数据长度=>" + data.Length);
try try
@ -47,19 +51,16 @@ namespace ServerCore.NetWork
/// 断开连接 /// 断开连接
/// </summary> /// </summary>
/// <param name="sk"></param> /// <param name="sk"></param>
public override void OnClose(AsyncUserToken token) public void OnDisconnect(AsyncUserToken token)
{
OnCloseToOld(token.Socket);
}
/// <summary>
/// 断开连接
/// </summary>
/// <param name="sk"></param>
public void OnCloseToOld(Socket sk)
{ {
Console.WriteLine("断开连接"); Console.WriteLine("断开连接");
ServerManager.g_ClientMgr.SetClientOfflineForSocket(sk); ServerManager.g_ClientMgr.SetClientOfflineForSocket(token.Socket);
} }
public void OnShowNetLog(string msg)
{
ServerManager.g_Log.Debug(msg);
}
} }
} }