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
327 lines
10 KiB
C#
327 lines
10 KiB
C#
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();
|
||
}
|
||
}
|
||
}
|
||
} |