Compare commits

..

No commits in common. "a43245ac0ee194a34456a4c0568675f31e8e3014" and "7eafd2e59d8cd8ff6e893e6aa4832fc589094c35" have entirely different histories.

14 changed files with 200 additions and 109 deletions

Binary file not shown.

View File

@ -111,7 +111,7 @@ namespace HaoYueNet.ClientNetworkNet4x
OnCloseReady();
return;
}
//LogOut("发送心跳包");
LogOut("发送心跳包");
}
/// <summary>
@ -229,7 +229,7 @@ namespace HaoYueNet.ClientNetworkNet4x
//不处理心跳包
if (data.Length == 1 && data[0] == 0x00)
{
//LogOut("收到心跳包");
LogOut("收到心跳包");
return;
}

View File

@ -44,48 +44,17 @@ namespace HaoYueNet.ServerNetwork
public BufferManager m_bufferManager;
public const int opsToAlloc = 2;
Socket listenSocket; //监听Socket
public SocketEventPool m_Receivepool;
public SocketEventPool m_pool;
public SocketEventPool m_Sendpool;
public TokenMsgPool msg_pool;
//public Dictionary<AsyncUserToken, SocketAsyncEventArgs> _DictAsyncUserTokenSendSAEA = new Dictionary<AsyncUserToken, SocketAsyncEventArgs>();
public int m_clientCount; //连接的客户端数量
public Semaphore m_maxNumberAcceptedClients;//信号量
public Semaphore m_maxNumberAcceptedClients;
List<AsyncUserToken> m_clients; //客户端列表
public 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
/// <summary>
@ -114,9 +83,12 @@ namespace HaoYueNet.ServerNetwork
/// 接收到客户端的数据事件
/// </summary>
public event OnReceiveData ReceiveClientData;
#endregion
#region
#region
/// <summary>
/// 获取客户端列表
/// </summary>
@ -134,10 +106,10 @@ namespace HaoYueNet.ServerNetwork
m_maxConnectNum = numConnections;
m_revBufferSize = receiveBufferSize;
// allocate buffers such that the maximum number of sockets can have one outstanding read and
//write posted to the socket simultaneously
//write posted to the socket simultaneously
m_bufferManager = new BufferManager(receiveBufferSize * numConnections * opsToAlloc, receiveBufferSize);
m_Receivepool = new SocketEventPool(numConnections);
m_pool = new SocketEventPool(numConnections);
m_Sendpool = new SocketEventPool(numConnections);
msg_pool = new TokenMsgPool(numConnections);
@ -162,21 +134,23 @@ namespace HaoYueNet.ServerNetwork
readWriteEventArg = new SocketAsyncEventArgs();
readWriteEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
readWriteEventArg.UserToken = new AsyncUserToken();
// assign a byte buffer from the buffer pool to the SocketAsyncEventArg object
m_bufferManager.SetBuffer(readWriteEventArg);
// add SocketAsyncEventArg to the pool
m_Receivepool.Push(readWriteEventArg);
m_pool.Push(readWriteEventArg);
}
//尝试
for (int i = 0; i < m_maxConnectNum; i++)
{
readWriteEventArg = new SocketAsyncEventArgs();
readWriteEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
readWriteEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed2);
readWriteEventArg.UserToken = new AsyncUserToken();
//发送是否需要如此设置 TODO
// assign a byte buffer from the buffer pool to the SocketAsyncEventArg object
m_bufferManager.SetBuffer(readWriteEventArg);
// add SocketAsyncEventArg to the pool
m_Sendpool.Push(readWriteEventArg);
}
}
@ -192,7 +166,7 @@ namespace HaoYueNet.ServerNetwork
{
try
{
ClearUserToken();
m_clients.Clear();
listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
if (bReuseAddress)
@ -242,7 +216,9 @@ namespace HaoYueNet.ServerNetwork
listenSocket.Close();
int c_count = m_clients.Count;
ClearUserToken();
lock (m_clients) { m_clients.Clear(); }
//补充处理
lock (_DictSocketAsyncUserToken) { _DictSocketAsyncUserToken.Clear(); }
if (ClientNumberChange != null)
ClientNumberChange(-c_count, null);
@ -298,7 +274,7 @@ namespace HaoYueNet.ServerNetwork
Interlocked.Increment(ref m_clientCount);
// Get the socket for the accepted client connection and put it into the
//ReadEventArg object user token
SocketAsyncEventArgs readEventArgs = m_Receivepool.Pop();
SocketAsyncEventArgs readEventArgs = m_pool.Pop();
AsyncUserToken userToken = (AsyncUserToken)readEventArgs.UserToken;
userToken.Socket = e.AcceptSocket;
userToken.ConnectTime = DateTime.Now;
@ -309,9 +285,13 @@ namespace HaoYueNet.ServerNetwork
userToken.RevIndex = MaxRevIndexNum;
userToken.SendIndex = MaxSendIndexNum;
AddUserToken(userToken);
lock (m_clients) { m_clients.Add(userToken); }
ClientNumberChange?.Invoke(1, userToken);
//补充处理
lock (_DictSocketAsyncUserToken) { _DictSocketAsyncUserToken.Add(userToken.Socket, userToken); }
if (ClientNumberChange != null)
ClientNumberChange(1, userToken);
if (!e.AcceptSocket.ReceiveAsync(readEventArgs))
{
ProcessReceive(readEventArgs);
@ -344,6 +324,22 @@ namespace HaoYueNet.ServerNetwork
}
}
void IO_Completed2(object sender, SocketAsyncEventArgs e)
{
// determine which type of operation just completed and call the associated handler
Console.WriteLine("就他妈从来没进过");
//switch (e.LastOperation)
//{
// case SocketAsyncOperation.Receive:
// ProcessReceive(e);
// break;
// case SocketAsyncOperation.Send:
// ProcessSend2(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.
// If the remote host closed the connection, then the socket is closed.
@ -404,9 +400,7 @@ namespace HaoYueNet.ServerNetwork
//继续接收. 为什么要这么写,请看Socket.ReceiveAsync方法的说明
if (!token.Socket.ReceiveAsync(e))
{
this.ProcessReceive(e);
}
}
else
{
@ -419,18 +413,51 @@ namespace HaoYueNet.ServerNetwork
}
}
// This method is invoked when an asynchronous send operation completes.
// The method issues another receive on the socket to read any additional
// data sent from the client
//
// <param name="e"></param>
private void ProcessSend(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
//TODO
// done echoing data back to the client
AsyncUserToken token = (AsyncUserToken)e.UserToken;
// read the next block of data send from the client
bool willRaiseEvent = token.Socket.ReceiveAsync(e);
if (!willRaiseEvent)
{
ProcessReceive(e);
}
}
else
{
CloseClientSocket(e);
return;
}
ReleaseSocketAsyncEventArgs(e);
}
private void ProcessSend2(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
// done echoing data back to the client
//AsyncUserToken token = (AsyncUserToken)e.UserToken;
// read the next block of data send from the client
//bool willRaiseEvent = token.Socket.ReceiveAsync(e);
//if (!willRaiseEvent)
//{
// ProcessReceive(e);
//}
}
else
{
CloseClientSocket(e);
}
e.SetBuffer(null, 0, 0);
m_Sendpool.Push(e);
//Console.WriteLine("发送完毕压进回对象池");
SendForMsgPool();
}
@ -442,7 +469,15 @@ namespace HaoYueNet.ServerNetwork
//调用关闭连接
OnClose(token);
RemoveUserToken(token);
lock (m_clients) { m_clients.Remove(token); }
//补充处理
lock (_DictSocketAsyncUserToken) { _DictSocketAsyncUserToken.Remove(token.Socket); }
////尝试1
//m_Sendpool.Push(_DictAsyncUserTokenSendSAEA[token]);
//lock (_DictAsyncUserTokenSendSAEA) { _DictAsyncUserTokenSendSAEA.Remove(token); }
////尝试1结束
//如果有事件,则调用事件,发送客户端数量变化通知
if (ClientNumberChange != null)
@ -458,24 +493,40 @@ namespace HaoYueNet.ServerNetwork
Interlocked.Decrement(ref m_clientCount);
m_maxNumberAcceptedClients.Release();
// Free the SocketAsyncEventArg so they can be reused by another client
ReleaseSocketAsyncEventArgs(e);
}
void ReleaseSocketAsyncEventArgs(SocketAsyncEventArgs saea)
{
saea.UserToken = null;//TODO
saea.SetBuffer(null, 0, 0);
switch (saea.LastOperation)
{
case SocketAsyncOperation.Receive:
m_Receivepool.Push(saea);
break;
case SocketAsyncOperation.Send:
m_Sendpool.Push(saea);
break;
}
e.UserToken = new AsyncUserToken();
m_pool.Push(e);
}
/// <summary>
/// 对数据进行打包,然后再发送
/// </summary>
/// <param name="token"></param>
/// <param name="message"></param>
/// <returns></returns>
//public void SendMessage(AsyncUserToken token, byte[] message)
//{
// if (token == null || token.Socket == null || !token.Socket.Connected)
// return;
// try
// {
// //对要发送的消息,制定简单协议,头4字节指定包的大小,方便客户端接收(协议可以自己定)
// byte[] buff = new byte[message.Length + 4];
// byte[] len = BitConverter.GetBytes(message.Length);
// Array.Copy(len, buff, 4);
// Array.Copy(message, 0, buff, 4, message.Length);
// //token.Socket.Send(buff); //这句也可以发送, 可根据自己的需要来选择
// //新建异步发送对象, 发送消息
// SocketAsyncEventArgs sendArg = new SocketAsyncEventArgs();
// sendArg.UserToken = token;
// sendArg.SetBuffer(buff, 0, buff.Length); //将数据放置进去.
// token.Socket.SendAsync(sendArg);
// }
// catch (Exception e)
// {
// //RuncomLib.Log.LogUtils.Info("SendMessage - Error:" + e.Message);
// }
//}
//bool flag_SendForMsgPool = false;
int sendrun = 0;
public void SendForMsgPool()
{
@ -510,43 +561,72 @@ namespace HaoYueNet.ServerNetwork
}
public void SendMessage(AsyncUserToken token, byte[] message,bool dontNeedHead = false)
public void SendMessage(AsyncUserToken token, byte[] message)
{
if (token == null || token.Socket == null || !token.Socket.Connected)
return;
try
{
if (!dontNeedHead)
{
message = SendDataWithHead(message);
}
message = SendDataWithHead(message);
//尝试2 (发送的时候从队列取,动态绑定
//Console.WriteLine("队列取出 并 发送!!!!");
if (m_Sendpool.Count > 0)
{
SocketAsyncEventArgs myreadEventArgs = m_Sendpool.Pop();
myreadEventArgs.UserToken = token;
myreadEventArgs.AcceptSocket = token.Socket;
myreadEventArgs.SetBuffer(message, 0, message.Length); //将数据放置进去.
token.Socket.SendAsync(myreadEventArgs);
//若不需要等待
if (!token.Socket.SendAsync(myreadEventArgs))
{
m_Sendpool.Push(myreadEventArgs);
}
//得了,先回去吧
m_Sendpool.Push(myreadEventArgs);
return;
}
else
{
//先压入队列等待m_Sendpool回收
msg_pool.Enqueue(new TokenWithMsg() { token = token, message = message });
//Console.WriteLine("压入消息发送队列MSG_Pool");
return;
}
//尝试结束
////尝试1
//Console.WriteLine("发送!!!!");
//SocketAsyncEventArgs myreadEventArgs;
//if (!_DictAsyncUserTokenSendSAEA.ContainsKey(token))
//{
// myreadEventArgs = m_Sendpool.Pop();
// myreadEventArgs.UserToken = token;
// _DictAsyncUserTokenSendSAEA.Add(token, myreadEventArgs);
// myreadEventArgs.AcceptSocket = token.Socket;
// //myreadEventArgs.AcceptSocket.RemoteEndPoint = token.Remote;
// token.IPAddress = ((IPEndPoint)(myreadEventArgs.AcceptSocket.RemoteEndPoint)).Address;
//}
//else
//{
// myreadEventArgs = _DictAsyncUserTokenSendSAEA[token];
//}
//myreadEventArgs.SetBuffer(message, 0, message.Length); //将数据放置进去.
//token.Socket.SendAsync(myreadEventArgs);
//return;
////尝试1结束
//新建异步发送对象, 发送消息
SocketAsyncEventArgs sendArg = new SocketAsyncEventArgs();
sendArg.UserToken = token;
sendArg.SetBuffer(message, 0, message.Length); //将数据放置进去.
token.Socket.SendAsync(sendArg);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
//RuncomLib.Log.LogUtils.Info("SendMessage - Error:" + e.Message);
}
}
//拼接长度
@ -592,7 +672,12 @@ namespace HaoYueNet.ServerNetwork
{
OnClose(token);
RemoveUserToken(token);
lock (m_clients) { m_clients.Remove(token); }
//补充处理
lock (_DictSocketAsyncUserToken) { _DictSocketAsyncUserToken.Remove(token.Socket); }
//如果有事件,则调用事件,发送客户端数量变化通知
if (ClientNumberChange != null)
@ -607,6 +692,15 @@ namespace HaoYueNet.ServerNetwork
// decrement the counter keeping track of the total number of clients connected to the server
Interlocked.Decrement(ref m_clientCount);
m_maxNumberAcceptedClients.Release();
//试着加入一个释放
//token.Socket.Dispose();
// Free the SocketAsyncEventArg so they can be reused by another client
//e.UserToken = new AsyncUserToken();
//m_pool.Push(e);
//这里直接注释了进程池,需要验证是否会出问题
}
/// <summary>
@ -660,9 +754,14 @@ namespace HaoYueNet.ServerNetwork
return;
try
{
//Console.WriteLine(DateTime.Now.ToString() + "发送心跳包");
Console.WriteLine(DateTime.Now.ToString() + "发送心跳包");
token.SendIndex = MaxSendIndexNum;
SendMessage(token, HeartbeatData, true);
//新建异步发送对象, 发送消息
SocketAsyncEventArgs sendArg = new SocketAsyncEventArgs();
sendArg.UserToken = token;
sendArg.SetBuffer(HeartbeatData, 0, HeartbeatData.Length); //将数据放置进去.
token.Socket.SendAsync(sendArg);
}
catch (Exception e)
{
@ -677,7 +776,7 @@ namespace HaoYueNet.ServerNetwork
if (data.Length == 1 && data[0] == 0x00)//心跳包
{
//Console.WriteLine("收到心跳包");
Console.WriteLine("收到心跳包");
//无处理
}
else
@ -703,6 +802,7 @@ namespace HaoYueNet.ServerNetwork
{
for (int i = 0; i < m_clients.Count(); i++)
{
//Console.WriteLine("RevIndex->{0} SendIndex->{1}", m_clients[i].RevIndex, m_clients[i].SendIndex);
//接收服务器数据计数
m_clients[i].RevIndex--;
if (m_clients[i].RevIndex <= 0)

View File

@ -1,26 +1,4 @@
# HaoYueNet
.Net 7 的自建基于IOCP的TCP的高性能网络库
使用Protobuff作为通讯协议
包含服务端和客户端双端库,可直接用于各类.Net程序或Unity程序做TCP通讯底层库。
不用关心网络底层,直接引用或继承,即可便捷使用。
DataCallBack//网络消息事件
OnClose//连接关闭
并包含心跳包等检测、连接管理、Protobuff解析优化后的高性能收发等等。
Simple目录下有实例客户端和实例服务端
示例中,使用本网络库,您可以继续示例项目写,也可以参照示例代码。
示例中实现了:
事件机制,
客户端基本框架(连接管理,数据管理,消息收发,指定用户发送)
服务端基本框架(连接管理,用户管理,消息收发,指定用户发送,广播等)
简单无OAuth登录
用户列表,
基础的Protobuff设计
基础聊天功能,
整合Protobuff生成。
您甚至可以
.Net 6的自建基于IOCP的TCP的高性能网络库
使用Protobuff作为通讯协议

View File

@ -10,7 +10,19 @@ namespace ServerCore.NetWork
public IOCPNetWork(int numConnections, int receiveBufferSize)
: base(numConnections, receiveBufferSize)
{
m_clientCount = 0;
m_maxConnectNum = numConnections;
m_revBufferSize = receiveBufferSize;
// allocate buffers such that the maximum number of sockets can have one outstanding read and
//write posted to the socket simultaneously
m_bufferManager = new BufferManager(receiveBufferSize * numConnections * opsToAlloc, receiveBufferSize);
m_pool = new SocketEventPool(numConnections);
m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections);
ClientNumberChange += IOCPNetWork_ClientNumberChange;
}
private void IOCPNetWork_ClientNumberChange(int num, AsyncUserToken token)
@ -61,5 +73,6 @@ namespace ServerCore.NetWork
Console.WriteLine("断开连接");
ServerManager.g_ClientMgr.SetClientOfflineForSocket(sk);
}
}
}