|
|
|
|
using System.Reflection;
|
|
|
|
|
using Autofac;
|
|
|
|
|
using Autofac.Core;
|
|
|
|
|
using DotNetty.Codecs;
|
|
|
|
|
using DotNetty.Common.Internal.Logging;
|
|
|
|
|
using DotNetty.Handlers.Logging;
|
|
|
|
|
using DotNetty.Handlers.Timeout;
|
|
|
|
|
using DotNetty.Transport.Bootstrapping;
|
|
|
|
|
using DotNetty.Transport.Channels;
|
|
|
|
|
using DotNetty.Transport.Channels.Sockets;
|
|
|
|
|
using HybirdFrameworkCore.Autofac;
|
|
|
|
|
using HybirdFrameworkCore.Autofac.Attribute;
|
|
|
|
|
using log4net;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using LogLevel = DotNetty.Handlers.Logging.LogLevel;
|
|
|
|
|
|
|
|
|
|
namespace HybirdFrameworkDriver.TcpServer;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// netty server
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class TcpServer<TH, TD, TE> : IDisposable where TH : IChannelHandler
|
|
|
|
|
where TD : ByteToMessageDecoder, new()
|
|
|
|
|
where TE : ChannelHandlerAdapter, new()
|
|
|
|
|
{
|
|
|
|
|
private static readonly ILog Log = LogManager.GetLogger(typeof(TcpServer<TH, TD, TE>));
|
|
|
|
|
|
|
|
|
|
private static MultithreadEventLoopGroup? bossGroup;
|
|
|
|
|
private static MultithreadEventLoopGroup? workerGroup;
|
|
|
|
|
private static ServerBootstrap? bootstrap;
|
|
|
|
|
|
|
|
|
|
private int _port = 9000;
|
|
|
|
|
|
|
|
|
|
public LogLevel? LogLevel { get; set; }
|
|
|
|
|
|
|
|
|
|
public Action? ChannelInActiveAction { get; set; }
|
|
|
|
|
|
|
|
|
|
public void InitBootstrap()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (LogLevel != null)
|
|
|
|
|
{
|
|
|
|
|
InternalLoggerFactory.DefaultFactory.AddProvider(new Log4NetProvider());
|
|
|
|
|
}
|
|
|
|
|
bossGroup = new MultithreadEventLoopGroup();
|
|
|
|
|
workerGroup = new MultithreadEventLoopGroup();
|
|
|
|
|
bootstrap = new ServerBootstrap();
|
|
|
|
|
bootstrap
|
|
|
|
|
.Group(bossGroup, workerGroup) // 设置主和工作线程组
|
|
|
|
|
.Channel<TcpServerSocketChannel>() // 设置通道模式为TcpSocket
|
|
|
|
|
.Option(ChannelOption.SoKeepalive, true) //保持连接
|
|
|
|
|
.Handler(new LoggingHandler())
|
|
|
|
|
.ChildHandler(new ActionChannelInitializer<ISocketChannel>(channel =>
|
|
|
|
|
{
|
|
|
|
|
var serverListenerHandler = new ServerListenerHandler<TH, TD, TE>
|
|
|
|
|
{
|
|
|
|
|
ChannelInActiveAction = ChannelInActiveAction
|
|
|
|
|
};
|
|
|
|
|
var pipeline = channel.Pipeline;
|
|
|
|
|
pipeline.AddLast(new LoggingHandler());
|
|
|
|
|
pipeline.AddLast(serverListenerHandler);
|
|
|
|
|
pipeline.AddLast(new IdleStateHandler(0, 0, 180)); //检测空闲连接
|
|
|
|
|
//业务handler ,这里是实际处理业务的Handler
|
|
|
|
|
|
|
|
|
|
ResolveEncode(pipeline);
|
|
|
|
|
ResolveDecode(pipeline);
|
|
|
|
|
ResolveHandler(pipeline);
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// ??netty
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
Log.Info(this + " Dispose");
|
|
|
|
|
bossGroup?.ShutdownGracefullyAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ResolveEncode(IChannelPipeline pipeline)
|
|
|
|
|
{
|
|
|
|
|
pipeline.AddLast(new TE());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ResolveDecode(IChannelPipeline pipeline)
|
|
|
|
|
{
|
|
|
|
|
pipeline.AddLast(new TD());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ResolveHandler(IChannelPipeline pipeline)
|
|
|
|
|
{
|
|
|
|
|
var list = new List<Type>();
|
|
|
|
|
|
|
|
|
|
foreach (var reg in AppInfo.Container.ComponentRegistry.Registrations)
|
|
|
|
|
foreach (var service in reg.Services)
|
|
|
|
|
if (service is TypedService ts)
|
|
|
|
|
if (MatchHandlers(ts))
|
|
|
|
|
list.Add(ts.ServiceType);
|
|
|
|
|
|
|
|
|
|
var handlers = new List<TH>();
|
|
|
|
|
foreach (var type in list)
|
|
|
|
|
{
|
|
|
|
|
var resolve = AppInfo.Container.Resolve(type);
|
|
|
|
|
handlers.Add((TH)resolve);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handlers.Sort((handler, msgHandler) =>
|
|
|
|
|
{
|
|
|
|
|
var orderAttribute1 = handler.GetType().GetCustomAttribute<OrderAttribute>();
|
|
|
|
|
var orderAttribute2 = msgHandler.GetType().GetCustomAttribute<OrderAttribute>();
|
|
|
|
|
var h1Order = orderAttribute1?.Order ?? 0;
|
|
|
|
|
var h2Order = orderAttribute2?.Order ?? 0;
|
|
|
|
|
return h1Order.CompareTo(h2Order);
|
|
|
|
|
});
|
|
|
|
|
foreach (var msgHandler in handlers) pipeline.AddLast(msgHandler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool MatchHandlers(TypedService ts)
|
|
|
|
|
{
|
|
|
|
|
var interfaces = ts.ServiceType.GetInterfaces();
|
|
|
|
|
if (interfaces.Length > 0)
|
|
|
|
|
foreach (var type in interfaces)
|
|
|
|
|
if (type == typeof(TH))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Start(int port)
|
|
|
|
|
{
|
|
|
|
|
_port = port;
|
|
|
|
|
Log.Info(" Start Listen");
|
|
|
|
|
InitBootstrap();
|
|
|
|
|
Task<IChannel>? channel = bootstrap?.BindAsync(_port);
|
|
|
|
|
Log.Info($"netty success listen {_port}");
|
|
|
|
|
}
|
|
|
|
|
}
|