using System;
using System.Net;
using System.Net.Sockets;
using AI.scripts.Managers.Server.Net;
using Godot;
using Protocol.Dto;
using 框架.Event;
using Semaphore = System.Threading.Semaphore;
namespace 服务器.Server.Net;
public class ServerPeer
{
private Socket _socket;
private Semaphore _semaphore;
private ClientPeerPool _clientPeerPool;
private IApplication _application;
public void SetApplication(IApplication application)
{
_application = application;
}
public void StartServer(string ip, int port, int maxClients)
{
try
{
_clientPeerPool = new ClientPeerPool(maxClients);
_semaphore = new Semaphore(maxClients, maxClients);
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 创建初始化客户端池
for (var i = 0; i < maxClients; i++)
{
ClientPeer clientPeer = new ClientPeer();
EventCenter.Instance.AddEventListener<ClientPeer, NetMsg>("Receive", ReceiveProcess);
clientPeer.ReceiveArgs.Completed += ReceiveArgsOnCompleted;
_clientPeerPool.Enqueue(clientPeer);
}
_socket.Bind(new IPEndPoint(IPAddress.Parse(ip), port));
_socket.Listen(maxClients);
GD.Print("[服务器]启动");
AcceptClient();
}
catch (SocketException e)
{
GD.PrintErr($"[服务器]报错位置:StartServer {e.Message}");
}
}
#region 接收客户端连接
/// <summary>
/// 接受客户端连接
/// </summary>
/// <param name="e"></param>
private void AcceptClient(SocketAsyncEventArgs e = null)
{
if (e == null)
{
e = new SocketAsyncEventArgs();
e.Completed += EOnCompleted;
}
var result = _socket.AcceptAsync(e);
if (result == false)
{
ProcessAccept(e);
}
}
/// <summary>
/// 处理客户端连接完成事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void EOnCompleted(object sender, SocketAsyncEventArgs e)
{
ProcessAccept(e);
}
/// <summary>
/// 处理客户端连接
/// </summary>
/// <param name="e"></param>
private void ProcessAccept(SocketAsyncEventArgs e)
{
_semaphore.WaitOne();
ClientPeer client = _clientPeerPool.Dequeue();
client.ClientSocket = e.AcceptSocket;
GD.Print($"[服务器]{client.ClientSocket?.RemoteEndPoint} 客户端连入");
StartReceive(client);
e.AcceptSocket = null;
AcceptClient(e);
}
#endregion
#region 接收数据
private void StartReceive(ClientPeer client)
{
try
{
var result = client.ClientSocket.ReceiveAsync(client.ReceiveArgs);
if (result == false)
{
ProcessReceive(client.ReceiveArgs);
}
}
catch (SocketException e)
{
GD.PrintErr($"[服务器]报错位置:StartReceive {e.Message}");
}
}
/// <summary>
/// 处理接收数据完成事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ReceiveArgsOnCompleted(object sender, SocketAsyncEventArgs e)
{
ProcessReceive(e);
}
/// <summary>
/// 处理接收数据
/// </summary>
/// <param name="e"></param>
private void ProcessReceive(SocketAsyncEventArgs e)
{
var client = e.UserToken as ClientPeer;
if (client?.ReceiveArgs.SocketError == SocketError.Success && client.ReceiveArgs.BytesTransferred > 0)
{
var packet = new byte[client.ReceiveArgs.BytesTransferred];
if (client.ReceiveArgs.Buffer == null) return;
Buffer.BlockCopy(client.ReceiveArgs.Buffer, 0, packet, 0,
client.ReceiveArgs.BytesTransferred);
client.ProcessReceive(packet);
StartReceive(client);
}
else //断开连接
{
if (client?.ReceiveArgs.BytesTransferred == 0)
{
// 主动断开连接
if (client.ReceiveArgs.SocketError == SocketError.Success)
{
DisconnectClient(client, "主动断开连接");
}
else if (client.ReceiveArgs.SocketError == SocketError.ConnectionReset)
{
DisconnectClient(client, client.ReceiveArgs.SocketError.ToString());
}
}
}
}
/// <summary>
/// 处理一条消息
/// </summary>
/// <param name="client"></param>
/// <param name="msg"></param>
private void ReceiveProcess(ClientPeer client, NetMsg msg)
{
// 应用层 处理消息
_application.Receive(client, msg);
}
#endregion
#region 断开连接
/// <summary>
/// 断开客户端连接
/// </summary>
/// <param name="client"></param>
/// <param name="reason"></param>
private void DisconnectClient(ClientPeer client, string reason)
{
try
{
if (client == null)
GD.PrintErr("客户端为空");
GD.Print($"[服务器]{client.ClientSocket?.RemoteEndPoint}客户端断开连接:{reason}");
_application.Disconnect(client);
//客户端断开连接
client.Disconnect();
//将断开连接的客户端添加到客户端池中
_clientPeerPool.Enqueue(client);
//释放信号量
_semaphore.Release();
}
catch (SocketException e)
{
GD.PrintErr($"[服务器]报错位置:DisconnectClient {e.Message}");
}
}
#endregion
}
版权属于:
chnenuo
作品采用:
《
署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
》许可协议授权
评论