Files
hjha-server/ServerCore/NetWork/TService.cs
xiaoou e9616125ce feat: initial commit - HJHA game server full source
6 major server modules (PdkFriendServer/GlobalSever/ServerCore/GameModule/GameNetModule) +
game logic (GameFix/GameDAL/ServerData) +
network layer (NetWorkMessage) +
data layer (ObjectModel) +
utilities (MrWu/Core/Config/CloudAPI/dll) +
adapters (zyxAdapter/base)

.NET 8.0 C# solution, 16 projects, 958 source files
2026-07-07 12:02:15 +08:00

327 lines
10 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using MrWu.Debug;
using NetWorkMessage;
namespace Server.Net
{
public enum TcpOp
{
StartSend,
StartRecv,
Connect,
}
public struct TArgs
{
public TcpOp Op;
public long ChannelId;
public SocketAsyncEventArgs SocketAsyncEventArgs;
}
public enum ServiceType
{
Router,
Actor,
}
public sealed class TService : AService
{
private readonly Dictionary<long, TChannel> idChannels = new Dictionary<long, TChannel>();
private readonly SocketAsyncEventArgs innArgs = new SocketAsyncEventArgs();
/// <summary>
/// 监听者
/// </summary>
private Socket acceptor;
public ConcurrentQueue<TArgs> Queue = new ConcurrentQueue<TArgs>();
public TService(ServiceType serviceType)
{
this.ServiceType = serviceType;
}
public TService(IPEndPoint ipEndPoint, ServiceType serviceType)
{
this.ServiceType = serviceType;
this.acceptor = new Socket(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
// 容易出问题,先注释掉,按需开启
//this.acceptor.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
this.innArgs.Completed += this.OnComplete;
try
{
this.acceptor.Bind(ipEndPoint);
}
catch (Exception e)
{
throw new Exception($"bind error: {ipEndPoint}", e);
}
//设置连接请求队列的最大长度不是只能有1000个链接
this.acceptor.Listen(1000);
this.AcceptAsync();
}
private void OnComplete(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Accept:
this.Queue.Enqueue(new TArgs() { SocketAsyncEventArgs = e });
break;
default:
throw new Exception($"socket error:{e.LastOperation}");
}
}
private void OnAcceptComplete(SocketError socketError, Socket acceptSocket)
{
if (this.acceptor == null)
{
return;
}
if (socketError != SocketError.Success)
{
Debug.Error($"accept error: {socketError}");
this.AcceptAsync();
return;
}
//有客户端连接成功
try
{
//创建Channel
long id = NetServices.CreateAcceptChannelId();
TChannel channel = new TChannel(id, acceptSocket, this);
this.idChannels.Add(channel.Id, channel);
long channelId = channel.Id;
this.AcceptCallBack(channelId, channel.RemoteAddress);
}
catch (Exception e)
{
Debug.Error($"TServiceCreateChannel:{e}");
}
this.AcceptAsync();
}
private void AcceptAsync()
{
this.innArgs.AcceptSocket = null;
if (this.acceptor.AcceptAsync(this.innArgs))
{
return;
}
OnAcceptComplete(this.innArgs.SocketError, this.innArgs.AcceptSocket);
}
public override void Create(long id, IPEndPoint ipEndPoint)
{
if (this.idChannels.TryGetValue(id, out TChannel _))
{
Debug.Error($"添加重复Channel:{id}");
return;
}
TChannel channel = new TChannel(id, ipEndPoint, this);
this.idChannels.Add(channel.Id, channel);
}
public TChannel Get(long id)
{
TChannel channel = null;
this.idChannels.TryGetValue(id, out channel);
return channel;
}
public override void Dispose()
{
Debug.Info("TChannel Dispose! --- ");
this.acceptor?.Close();
this.acceptor = null;
this.innArgs.Dispose();
foreach (var id in this.idChannels.Keys.ToArray())
{
TChannel channel = this.idChannels[id];
channel.Dispose();
}
this.idChannels.Clear();
}
public override void Remove(long id, int error = 0)
{
if (this.idChannels.TryGetValue(id, out TChannel channel))
{
channel.Error = error;
channel.Dispose();
}
this.idChannels.Remove(id);
}
public override void Send(long channelId, MemoryBuffer memoryBuffer)
{
#if DEBUG
ServiceThreadManager.Instance.CheckThread(this,Thread.CurrentThread.ManagedThreadId);
#endif
try
{
TChannel channel = this.Get(channelId);
if (channel == null)
{
//Debug.Log("channel is null!");
this.ErrorCallBack(channelId, NetErrorCode.ERR_SendMessageNotFoundTChannel);
return;
}
//Debug.Log("TChannel Send!");
channel.Send(memoryBuffer);
}
catch (Exception e)
{
Debug.Error($"TService Send:{e}");
}
}
public override void Update()
{
while (true)
{
if (!this.Queue.TryDequeue(out var result))
{
break;
}
SocketAsyncEventArgs e = result.SocketAsyncEventArgs;
if (e == null)
{
switch (result.Op)
{
case TcpOp.StartSend:
{
//Debug.Log("开始发送!");
TChannel channel = this.Get(result.ChannelId);
if (channel != null)
{
channel.StartSend();
}
break;
}
case TcpOp.StartRecv:
{
TChannel channel = this.Get(result.ChannelId);
if (channel != null)
{
channel.StartRecv();
}
break;
}
case TcpOp.Connect:
{
Debug.Log("链接!");
TChannel channel = this.Get(result.ChannelId);
if (channel != null)
{
channel.ConnectAsync();
}
break;
}
}
continue;
}
switch (e.LastOperation)
{
//监听
case SocketAsyncOperation.Accept:
{
SocketError socketError = e.SocketError;
Socket acceptSocket = e.AcceptSocket;
this.OnAcceptComplete(socketError, acceptSocket);
break;
}
//链接
case SocketAsyncOperation.Connect:
{
TChannel channel = this.Get(result.ChannelId);
if (channel != null)
{
channel.OnConnectComplete(e);
}
break;
}
//断开
case SocketAsyncOperation.Disconnect:
{
TChannel channel = this.Get(result.ChannelId);
if (channel != null)
{
channel.OnDisconnectComplete(e);
}
break;
}
//接收
case SocketAsyncOperation.Receive:
{
TChannel channel = this.Get(result.ChannelId);
if (channel != null)
{
channel.OnRecvComplete(e);
}
break;
}
//发送
case SocketAsyncOperation.Send:
{
TChannel channel = this.Get(result.ChannelId);
if (channel != null)
{
channel.OnSendComplete(e);
}
break;
}
default:
throw new ArgumentOutOfRangeException($"Tservice Update Error: {e.LastOperation}");
}
}
}
public override bool IsDisposed()
{
return this.acceptor == null;
}
public void Log()
{
Debug.ImportantLog($"当前真实链接数:{idChannels.Count}");
foreach (var kv in idChannels)
{
kv.Value.Log();
}
}
}
}