DotNetty使用之心跳机制

因为DotNetty是从java的Netty框架仿写过来的,介绍的文档特别少,加之官方也没有提供api文档,所以之前一直不理解心跳的用法。最近忙里偷闲,稍稍研究了一番,终于有点明白了。

现在将代码复制上来,留作日后查看(ps:精髓都在代码里):

Uptime.Client:

public class Program
    {
        const string HOST = "127.0.0.1";
        const int PORT = 8045;
        // Sleep 5 seconds before a reconnection attempt.
        public const int RECONNECT_DELAY = 5;
        // Reconnect when the server sends nothing for 10 seconds.
        private const int READ_TIMEOUT = 10;

        private static UptimeClientHandler handler = new UptimeClientHandler();
        private static Bootstrap bs = new Bootstrap();

        static void Main(string[] args)
        {
            EventLoopGroup group = new EventLoopGroup();
            bs.Group(group)
                .Channel()
                .RemoteAddress(HOST, PORT)
                 .Handler(new ActionChannelInitializer(channel =>
                 {
                     //IdleStateHandler心跳检测处理器,添加自定义处理Handler类实现userEventTriggered()方法作为超时事件的逻辑处理
                     //IdleStateHandler心跳检测每十秒进行一次读检测,如果十秒内ChannelRead()方法未被调用则触发一次userEventTrigger()方法.
                     IChannelPipeline pipeline = channel.Pipeline;
                     pipeline.AddLast(new IdleStateHandler(READ_TIMEOUT, 0, 0), handler);//第一个参数为读,第二个为写,第三个为读写全部

                 }));
        }
    }

Uptime.Client.UptimeClientHandler:

 public class UptimeClientHandler : SimpleChannelInboundHandler
    {
        long startTime = -1;

        //ChannelActive:活跃状态,可接收和发送数据
        public override void ChannelActive(IChannelHandlerContext ctx)
        {
            if (startTime < 0)
            {
                startTime = GetTimeStamp();
            }
           Console.WriteLine("Connected to: " + ctx.Channel.RemoteAddress);
        }

        protected override void ChannelRead0(IChannelHandlerContext context, object message)
        {
            var byteBuffer = message as IByteBuffer;
            if (byteBuffer != null)
            {
                Console.WriteLine("Received from server: " + byteBuffer.ToString(Encoding.UTF8));
            }
            context.WriteAsync(message);
        }

        public override void UserEventTriggered(IChannelHandlerContext ctx, object evt)
        {
            if (!(evt is IdleStateEvent)) 
            {
                return;
            }

            IdleStateEvent e = evt as IdleStateEvent;
            if (e.State == IdleState.ReaderIdle)
            {
                // The connection was OK but there was no traffic for last period.
                Console.WriteLine("Disconnecting due to no inbound traffic");
                ctx.CloseAsync();
            }
        }

        //channelInactive: 处于非活跃状态,没有连接到远程主机。
        public override void ChannelInactive(IChannelHandlerContext context)
        {
            Console.WriteLine("Disconnected from: " + context.Channel.RemoteAddress);
        }

        //channelUnregistered: 已创建但未注册到一个 EventLoop。
        public override void ChannelUnregistered(IChannelHandlerContext context)
        {
            
        }
  
        public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
        {
            Console.WriteLine("Exception: " + exception);
            context.CloseAsync();
        }

        /// 
        /// 获取时间戳
        /// 
        /// 
        private long GetTimeStamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalMilliseconds);
        }

    } 
  

Uptime.Server:

class Program
    {
        private static readonly int PORT = 8045;
        private static readonly UptimeServerHandler handler = new UptimeServerHandler();

        static void Main(string[] args) => RunServerAsync().Wait();

        static async Task RunServerAsync()
        {
            IEventLoopGroup bossGroup = new MultithreadEventLoopGroup(1);
            IEventLoopGroup workerGroup = new MultithreadEventLoopGroup();
            try
            {
                ServerBootstrap b = new ServerBootstrap();
                b.Group(bossGroup, workerGroup)
                    .Channel()
                      .Handler(new LoggingHandler("SRV-LSTN"))
                      .ChildHandler(new ActionChannelInitializer(channel =>
                      {
                          //工作线程连接器 是设置了一个管道,服务端主线程所有接收到的信息都会通过这个管道一层层往下传输
                          //同时所有出栈的消息也要这个管道的所有处理器进行一步步处理
                          IChannelPipeline pipeline = channel.Pipeline;
                          pipeline.AddLast("Uptime", handler);
                      }));

                // Bind and start to accept incoming connections.
                IChannel boundChannel = await b.BindAsync(PORT);

                // Wait until the server socket is closed.
                // In this example, this does not happen, but you can do that to gracefully
                // shut down your server.
                await boundChannel.CloseAsync();
            }
            finally
            {
                await Task.WhenAll(
                     bossGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)),
                     workerGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)));
            }
        }
    }

Uptime.Server.UptimeServerHandler:

 public class UptimeServerHandler : SimpleChannelInboundHandler {
 
        protected override void ChannelRead0(IChannelHandlerContext ctx, object msg)
        {
            // discard
        }

        //捕获 异常,并输出到控制台后断开链接,提示:客户端意外断开链接,也会触发
        public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
        {
            Console.WriteLine("Exception: " + exception);
            context.CloseAsync();
        }
    } 
  

最后,附上参考文档链接:DotNetty系列三:编码解码器,IdleStateHandler心跳机制,群发

你可能感兴趣的:(通信)