• Netty客户端与服务器端闲暇检测与心跳检测(三)


         网络应用程序中普遍存在一个问题:连接假死,连接假死现象是:在某一端(服务器端|客户端)看来,底层的TCP连接已经断开,但是应用程序没有捕获到,因此会认为这个连接还存在。从TCP层面来说,只有收到四次握手数据包,或者一个RST数据包,才表示连接状态已断开;

          连接假死会带来以下两大问题:

    1.对于服务来说,因为每个连接都会消耗CPU和内存资源,大量的假死的连接会逐渐消耗光服务器的资源,最终导致性能逐渐下降,程序崩溃;

    2.对应客户端来说,连接假死会造成发送数据超时,影响用户体验.

    通常,连接假死由下面的几个原因造成.

    1.应用程序出现线程阻塞,无法进行数据的读写.

    2.客户端或者服务器端网络相关设备出现故障,别网卡,或者机房.....

    3.公网丢包。公共网络相对内网而言,非常容易出现丢包,网络抖动等现象,如果在一段时间内用户接入的网络连接出现丢包现象,那么对于客户端来说,数据一直发送不出去,而服务端也一直收不到客户端的数据,连接一直这样耗着.

    如果应用程序时面向用户的,那么公网丢包这个问题出现的概率是非常高的,对于内网来说丢包,网络抖动也会有一定概率发生;

    下面我们从服务端与客户端分别来处理,需要完成服务端与客户端的闲暇假死检测和服务端与客户端的心跳检测:

    (一)闲暇检测:直接上检测的代码:

    1. ========================客户端与服务器端代码一样================================
    2. (客户端定时向服务器端发送闲暇检测|服务端定时向服务器端发送闲暇检测)
    3. ===============Netty框架为我们提交了一个实现了IdleStateHandler======================
    4. package org.jy.sso.websocket.stomp.push.netty.chat.system.chathandler;
    5. import io.netty.channel.ChannelHandlerContext;
    6. import io.netty.handler.timeout.IdleStateEvent;
    7. import io.netty.handler.timeout.IdleStateHandler;
    8. import lombok.extern.slf4j.Slf4j;
    9. import java.util.concurrent.TimeUnit;
    10. /**
    11. * 客户端闲暇心跳检测
    12. */
    13. @Slf4j
    14. public class ChatIMIdleStateHandler extends IdleStateHandler {
    15. private static final int READER_IDLE_TIME = 20;
    16. public ChatIMIdleStateHandler() {
    17. super(READER_IDLE_TIME, 0, 0, TimeUnit.SECONDS);
    18. }
    19. /**
    20. * 监听10分钟没有读或者写的时候关闭管道
    21. * @param ctx
    22. * @param evt
    23. */
    24. @Override
    25. protected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) {
    26. log.info(READER_IDLE_TIME + " 秒内未读到数据,关闭连接");
    27. ctx.flush();
    28. ctx.channel().close();
    29. }
    30. }

    下面分别在客户端与服务器端配置闲暇检测: 服务器端代码

    1. package org.jy.sso.websocket.stomp.push.netty.chat.system.chatcenter;
    2. import io.netty.bootstrap.ServerBootstrap;
    3. import io.netty.channel.ChannelInitializer;
    4. import io.netty.channel.ChannelOption;
    5. import io.netty.channel.nio.NioEventLoopGroup;
    6. import io.netty.channel.socket.nio.NioServerSocketChannel;
    7. import io.netty.channel.socket.nio.NioSocketChannel;
    8. import lombok.SneakyThrows;
    9. import org.jy.sso.websocket.stomp.push.netty.chat.system.chathandler.ChatIMIdleStateHandler;
    10. import org.jy.sso.websocket.stomp.push.netty.chat.system.chathandler.ChatPacketCodecHandler;
    11. import org.jy.sso.websocket.stomp.push.netty.chat.system.chathandler.server.ChatHeartBeatRequestHandler;
    12. /**
    13. * IM服务器端
    14. */
    15. public class ChatCenterServer {
    16. @SneakyThrows
    17. public static void main(String[] args) {
    18. // 服务器端启动类
    19. ServerBootstrap serverBootstrap = new ServerBootstrap();
    20. // boss主线程(父线程)
    21. NioEventLoopGroup bossLoopGroup = new NioEventLoopGroup();
    22. // 工作线程(子线程)
    23. NioEventLoopGroup workerLoopGroup = new NioEventLoopGroup();
    24. serverBootstrap // 父子线程建立组连接
    25. .group(bossLoopGroup, workerLoopGroup)
    26. .channel(NioServerSocketChannel.class)
    27. .option(ChannelOption.SO_BACKLOG, 1024)
    28. .childOption(ChannelOption.SO_KEEPALIVE, true)
    29. .childOption(ChannelOption.TCP_NODELAY, true)
    30. .childHandler(new ChannelInitializer() {
    31. @Override
    32. protected void initChannel(NioSocketChannel channel) {
    33. // 闲暇检测
    34. channel.pipeline().addLast(new ChatIMIdleStateHandler());
    35. channel.pipeline().addLast(ChatPacketCodecHandler.INSTANCE);
    36. channel.pipeline().addLast(ChatHeartBeatRequestHandler.INSTANCE);
    37. }
    38. }).bind(8000).sync();
    39. }
    40. }

    下面分别在客户端与服务器端配置闲暇检测: 客户端代码

    1. package org.jy.sso.websocket.stomp.push.netty.chat.system.chatcenter;
    2. import io.netty.bootstrap.Bootstrap;
    3. import io.netty.buffer.ByteBuf;
    4. import io.netty.channel.Channel;
    5. import io.netty.channel.ChannelFuture;
    6. import io.netty.channel.ChannelInitializer;
    7. import io.netty.channel.ChannelOption;
    8. import io.netty.channel.nio.NioEventLoopGroup;
    9. import io.netty.channel.socket.nio.NioSocketChannel;
    10. import lombok.SneakyThrows;
    11. import lombok.extern.slf4j.Slf4j;
    12. import org.apache.commons.lang.time.DateFormatUtils;
    13. import org.jy.sso.websocket.stomp.push.netty.chat.system.chatcommond.ChatRetryCommand;
    14. import org.jy.sso.websocket.stomp.push.netty.chat.system.chatedcode.PacketDecoder;
    15. import org.jy.sso.websocket.stomp.push.netty.chat.system.chatedcode.PacketEncodeDecode;
    16. import org.jy.sso.websocket.stomp.push.netty.chat.system.chatedcode.PacketEncoder;
    17. import org.jy.sso.websocket.stomp.push.netty.chat.system.chathandler.ChatIMIdleStateHandler;
    18. import org.jy.sso.websocket.stomp.push.netty.chat.system.chathandler.client.ChatHeartBeatResponseHandler;
    19. import org.jy.sso.websocket.stomp.push.netty.chat.system.chathandler.client.ChatLoginServerResponseHandler;
    20. import org.jy.sso.websocket.stomp.push.netty.chat.system.chathandler.client.ChatServerMessageResponseHandler;
    21. import org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatMessageRequestPacket;
    22. import org.jy.sso.websocket.stomp.push.netty.chat.system.constant.ChatClientConstant;
    23. import java.util.Date;
    24. import java.util.Scanner;
    25. import java.util.concurrent.ConcurrentHashMap;
    26. import java.util.concurrent.TimeUnit;
    27. /**
    28. *
    29. *

    30. * 工具主要是封装了java.util.Random对象,提供了一些产生随机数或者随机字符串的方法。随机工具类是RandomUtil,里面的方法都是静态方法。
    31. *

    32. * 673,798 访问数
    33. */
    34. @Slf4j
    35. public class ChatCenterClient {
    36. public static final ConcurrentHashMap bootStrapMap = new ConcurrentHashMap();
    37. @SneakyThrows
    38. public static void main(String[] args) {
    39. Bootstrap bootstrap = new Bootstrap();
    40. NioEventLoopGroup group = new NioEventLoopGroup();
    41. bootstrap.group(group)
    42. .channel(NioSocketChannel.class)
    43. .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
    44. .option(ChannelOption.SO_KEEPALIVE, true)
    45. .option(ChannelOption.TCP_NODELAY, true)
    46. .handler(new ChannelInitializer() {
    47. @Override
    48. protected void initChannel(Channel channel) {
    49. // 闲暇检测
    50. channel.pipeline().addLast(new ChatIMIdleStateHandler());
    51. channel.pipeline().addLast(new PacketDecoder());
    52. channel.pipeline().addLast(new PacketEncoder());
    53. // 心跳定时器
    54. channel.pipeline().addLast(new ChatHeartBeatResponseHandler());
    55. }
    56. });
    57. connect(bootstrap, ChatClientConstant.CHAT_SERVER_HOST_IP, ChatClientConstant.CHAT_SERVER_PORT, ChatClientConstant.CHAT_MAX_RETRY_NUM);
    58. // 重连指令与对应客户端启动的实例映射关系
    59. bootStrapMap.put(ChatRetryCommand.CHAT_RETRY_CONNECTION, bootstrap);
    60. }
    61. /**
    62. * @param bootstrap 客户端启动器
    63. * @param host 主机
    64. * @param port 端口
    65. * @param retryNum 指数退避重新连接的次数
    66. * @author yh19166
    67. * @deprecated 连接和重连机制,实现了指数退避重连
    68. */
    69. private static void connect(Bootstrap bootstrap, String host, int port, int retryNum) {
    70. bootstrap.connect(host, port).addListener(future -> {
    71. // 通过future.isSuccess() 判断是否连接成功
    72. if (future.isSuccess()) {
    73. System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + " -->> 连接成功....");
    74. } else if (retryNum == ChatClientConstant.CHAT_INI_RETRY_NUM) {
    75. System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + " -->> 重连次数已用完,放弃连接....");
    76. System.exit(0);
    77. } else {
    78. // 第几次重连
    79. int order = (ChatClientConstant.CHAT_MAX_RETRY_NUM - retryNum) + ChatClientConstant.CHAT_STEP_RETRY_LENGTH;
    80. // 客户考虑重新连接的逻辑,分梯度连接......
    81. System.out.println("第 " + order + " 连接失败......");
    82. // 本次重连的间隔: 通过左移操作快速计算出重连时间间隔
    83. int delay = ChatClientConstant.CHAT_STEP_RETRY_LENGTH << order;
    84. System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + " -->> 连接失败,第" + order + "次重新连接....");
    85. // 实现定时任务逻辑
    86. bootstrap.config().group().schedule(() -> connect(bootstrap, host, port, retryNum - ChatClientConstant.CHAT_STEP_RETRY_LENGTH), delay, TimeUnit.SECONDS);
    87. }
    88. });
    89. }
    90. /**
    91. * @param bootstrap 客户端启动类
    92. * @param host 主机
    93. * @param port 端口
    94. * @param retryNum 指数退避重新连接的次数
    95. * @author yh19166
    96. * @deprecated 连接和重连机制,实现了指数退避重连
    97. */
    98. @Deprecated
    99. public static void retryConnect(Bootstrap bootstrap, String host, int port, int retryNum) {
    100. bootstrap.connect(host, port).addListener(future -> {
    101. if (future.isSuccess()) {
    102. log.info("连接服务器成功!");
    103. Channel channel = ((ChannelFuture) future).channel();
    104. System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + " -->> 连接成功....");
    105. // 连接成功后启动控制台线程
    106. startConsoleTask(channel);
    107. } else if (retryNum == ChatClientConstant.CHAT_INI_RETRY_NUM) {
    108. log.error("重连次数已用完,放弃连接!");
    109. System.exit(0);
    110. } else {
    111. // 第几次重连
    112. int order = (ChatClientConstant.CHAT_MAX_RETRY_NUM - retryNum) + ChatClientConstant.CHAT_STEP_RETRY_LENGTH;
    113. // 本次重连的间隔
    114. int delay = ChatClientConstant.CHAT_STEP_RETRY_LENGTH << order;
    115. log.error(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + ": 连接失败,第" + order + "次重新连接....");
    116. bootstrap.config().group().schedule(() -> connect(bootstrap, host, port, retryNum - ChatClientConstant.CHAT_STEP_RETRY_LENGTH), delay, TimeUnit.SECONDS);
    117. }
    118. });
    119. }
    120. }

    至此服务端与客户端的闲暇检测依据配置完成

    (二)客户端与服务器端心跳检测

    通常服务器端未收到客户端的数据,这个现象产生的原因可分为两种情况:

    1,连接假死

    2,非假死状态下确实没有发送数据

    我们只需要排除第二种情况,那么自然就是连接假死。要排除第二种情况,我们客户定期发送数据包到服务器端,这里的数据包通常称之为心跳数据包,服务器端收到数据包后,把响应数据包发送到客户端。

    ===========================================================================

    直接上客户端心跳数据定时发送代码:

    1. package org.jy.sso.websocket.stomp.push.netty.chat.system.chathandler.client;
    2. import cn.hutool.core.date.DateUtil;
    3. import com.alibaba.fastjson.JSONObject;
    4. import io.netty.channel.ChannelHandlerContext;
    5. import io.netty.channel.SimpleChannelInboundHandler;
    6. import lombok.extern.slf4j.Slf4j;
    7. import org.apache.commons.lang.builder.ReflectionToStringBuilder;
    8. import org.apache.commons.lang.builder.ToStringStyle;
    9. import org.apache.commons.lang.time.DateFormatUtils;
    10. import org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket;
    11. import org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.response.ChatHeartBeatResponsePacket;
    12. import java.util.Date;
    13. import java.util.concurrent.TimeUnit;
    14. /**
    15. * 客户端心跳检测包
    16. */
    17. @Slf4j
    18. public class ChatHeartBeatResponseHandler extends SimpleChannelInboundHandler {
    19. private static final int HEARTBEAT_INTERVAL = 5;
    20. /**
    21. * 通道处于就绪状态
    22. *
    23. * @param ctx 通道上下文
    24. * @throws Exception 抛出异常信息
    25. */
    26. @Override
    27. public void channelActive(ChannelHandlerContext ctx) throws Exception {
    28. scheduleSendHeartBeat(ctx);
    29. super.channelActive(ctx);
    30. }
    31. private void scheduleSendHeartBeat(ChannelHandlerContext ctx) {
    32. ctx.executor().schedule(() -> {
    33. if (ctx.channel().isActive()) {
    34. ChatHeartBeatRequestPacket chatHeartBeatRequestPacket = new ChatHeartBeatRequestPacket();
    35. chatHeartBeatRequestPacket.setRequestTime(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS"));
    36. ctx.writeAndFlush(chatHeartBeatRequestPacket);
    37. System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + " : 客户端每间隔" + HEARTBEAT_INTERVAL + "秒向服务器端发送心跳数据包: " + ReflectionToStringBuilder.toString(chatHeartBeatRequestPacket,ToStringStyle.MULTI_LINE_STYLE));
    38. scheduleSendHeartBeat(ctx);
    39. } else {
    40. System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + " : 客户端通道已关闭,通道是否激活: " + ctx.channel().isActive());
    41. }
    42. }, HEARTBEAT_INTERVAL, TimeUnit.SECONDS);
    43. }
    44. /**
    45. * 读取服务端返回的心跳包
    46. * @param ctx 通道处理器上下文
    47. * @param chatHeartBeatResponsePacket 服务端响应的心跳包
    48. * @throws Exception 抛出异常
    49. */
    50. @Override
    51. protected void channelRead0(ChannelHandlerContext ctx, ChatHeartBeatResponsePacket chatHeartBeatResponsePacket) throws Exception {
    52. System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + " : 客户端收到服务器端的心跳包: " + ReflectionToStringBuilder.toString(chatHeartBeatResponsePacket,ToStringStyle.MULTI_LINE_STYLE));
    53. }
    54. }

     心跳响应数据包:

    1. package org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.response;
    2. import lombok.Data;
    3. import org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.DataPacket;
    4. import static org.jy.sso.websocket.stomp.push.netty.chat.system.chatcommond.ChatCommand.HEARTBEAT_RESPONSE_COMMAND;
    5. /**
    6. * 心跳数据响应包
    7. */
    8. @Data
    9. public class ChatHeartBeatResponsePacket extends DataPacket {
    10. private String responseTime;
    11. @Override
    12. public Byte getCommand() {
    13. return HEARTBEAT_RESPONSE_COMMAND;
    14. }
    15. }

     ======================================================================

    服务器端处理客户端发送的心跳包代码:

    1. package org.jy.sso.websocket.stomp.push.netty.chat.system.chathandler.server;
    2. import io.netty.channel.ChannelHandler;
    3. import io.netty.channel.ChannelHandlerContext;
    4. import io.netty.channel.SimpleChannelInboundHandler;
    5. import lombok.extern.slf4j.Slf4j;
    6. import org.apache.commons.lang.builder.ReflectionToStringBuilder;
    7. import org.apache.commons.lang.builder.ToStringStyle;
    8. import org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket;
    9. import org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.response.ChatHeartBeatResponsePacket;
    10. /**
    11. * 系统心跳请求数据包处理器
    12. */
    13. @Slf4j
    14. @ChannelHandler.Sharable
    15. public class ChatHeartBeatRequestHandler extends SimpleChannelInboundHandler {
    16. public static final ChatHeartBeatRequestHandler INSTANCE = new ChatHeartBeatRequestHandler();
    17. private ChatHeartBeatRequestHandler() {
    18. }
    19. @Override
    20. protected void channelRead0(ChannelHandlerContext ctx, ChatHeartBeatRequestPacket chatMessageRequestPacket) {
    21. System.out.println("服务器端收到的客户端心跳检测消息: " + ReflectionToStringBuilder.toString(chatMessageRequestPacket, ToStringStyle.MULTI_LINE_STYLE));
    22. ChatHeartBeatResponsePacket chatHeartBeatResponsePacket = new ChatHeartBeatResponsePacket();
    23. chatHeartBeatResponsePacket.setResponseTime(chatMessageRequestPacket.getRequestTime());
    24. chatHeartBeatResponsePacket.setVersion(chatMessageRequestPacket.getVersion());
    25. ctx.writeAndFlush(chatHeartBeatResponsePacket);
    26. }
    27. }

    心跳请求数据包:

    1. package org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request;
    2. import lombok.Data;
    3. import org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.DataPacket;
    4. import static org.jy.sso.websocket.stomp.push.netty.chat.system.chatcommond.ChatCommand.HEARTBEAT_REQUEST_COMMAND;
    5. /**
    6. * 心跳请求数据包
    7. */
    8. @Data
    9. public class ChatHeartBeatRequestPacket extends DataPacket {
    10. private String requestTime;
    11. @Override
    12. public Byte getCommand() {
    13. return HEARTBEAT_REQUEST_COMMAND;
    14. }
    15. }

    至此,心跳检测,闲暇检测已完成, 闲暇检测与心跳检查配置如上客户端与服务端处理器的配置;

    测试数据:

       心跳检测的日志: 

    1. 客户端日志:
    2. 14:28:10.304 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.smallCacheSize: 256
    3. 14:28:10.304 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.normalCacheSize: 64
    4. 14:28:10.304 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxCachedBufferCapacity: 32768
    5. 14:28:10.304 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.cacheTrimInterval: 8192
    6. 14:28:10.321 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.allocator.type: pooled
    7. 14:28:10.322 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.threadLocalDirectBufferSize: 65536
    8. 14:28:10.322 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.maxThreadLocalCharBufferSize: 16384
    9. 2023-05-28 14:28:10.373 -->> 连接成功....
    10. 输入发送到服务器端内容:
    11. 14:28:15.448 [nioEventLoopGroup-2-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxCapacityPerThread: 32768
    12. 14:28:15.448 [nioEventLoopGroup-2-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxSharedCapacityFactor: 2
    13. 14:28:15.448 [nioEventLoopGroup-2-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.linkCapacity: 16
    14. 14:28:15.448 [nioEventLoopGroup-2-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.ratio: 8
    15. 14:28:15.464 [nioEventLoopGroup-2-1] DEBUG io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.bytebuf.checkAccessible: true
    16. 14:28:15.466 [nioEventLoopGroup-2-1] DEBUG io.netty.util.ResourceLeakDetectorFactory - Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector@aeadd3
    17. 2023-05-28 14:28:15.614 : 客户端每间隔5秒向服务器端发送心跳数据包: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket@af1a9f[
    18. requestTime=2023-05-28 14:28:15.398
    19. version=1
    20. ]
    21. 2023-05-28 14:28:15.874 : 客户端收到服务器端的心跳包: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.response.ChatHeartBeatResponsePacket@1de699a[
    22. responseTime=2023-05-28 14:28:15.398
    23. version=1
    24. ]
    25. 2023-05-28 14:28:20.630 : 客户端每间隔5秒向服务器端发送心跳数据包: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket@1b10535[
    26. requestTime=2023-05-28 14:28:20.629
    27. version=1
    28. ]
    29. 2023-05-28 14:28:20.631 : 客户端收到服务器端的心跳包: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.response.ChatHeartBeatResponsePacket@1bf5daa[
    30. responseTime=2023-05-28 14:28:20.629
    31. version=1
    32. ]
    33. 2023-05-28 14:28:25.631 : 客户端每间隔5秒向服务器端发送心跳数据包: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket@618c9d[
    34. requestTime=2023-05-28 14:28:25.631
    35. version=1
    36. ]
    37. 2023-05-28 14:28:25.632 : 客户端收到服务器端的心跳包: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.response.ChatHeartBeatResponsePacket@83a8b2[
    38. responseTime=2023-05-28 14:28:25.631
    39. version=1
    40. ]
    41. 2023-05-28 14:28:30.633 : 客户端每间隔5秒向服务器端发送心跳数据包: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket@1c49c3a[
    42. requestTime=2023-05-28 14:28:30.633
    43. version=1
    44. ]
    45. 2023-05-28 14:28:30.634 : 客户端收到服务器端的心跳包: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.response.ChatHeartBeatResponsePacket@9fd965[
    46. responseTime=2023-05-28 14:28:30.633
    47. version=1
    48. ]
    49. 2023-05-28 14:28:35.634 : 客户端每间隔5秒向服务器端发送心跳数据包

    ===========================================================================

    1. 服务器端日志:
    2. 14:28:02.672 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.allocator.type: pooled
    3. 14:28:02.672 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.threadLocalDirectBufferSize: 65536
    4. 14:28:02.672 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.maxThreadLocalCharBufferSize: 16384
    5. 14:28:15.620 [nioEventLoopGroup-3-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxCapacityPerThread: 32768
    6. 14:28:15.620 [nioEventLoopGroup-3-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxSharedCapacityFactor: 2
    7. 14:28:15.620 [nioEventLoopGroup-3-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.linkCapacity: 16
    8. 14:28:15.620 [nioEventLoopGroup-3-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.ratio: 8
    9. 14:28:15.638 [nioEventLoopGroup-3-1] DEBUG io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.bytebuf.checkAccessible: true
    10. 14:28:15.641 [nioEventLoopGroup-3-1] DEBUG io.netty.util.ResourceLeakDetectorFactory - Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector@14711d0
    11. 服务器端收到的客户端心跳检测消息: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket@1e1c50[
    12. requestTime=2023-05-28 14:28:15.398
    13. version=1
    14. ]
    15. 服务器端收到的客户端心跳检测消息: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket@1fc82e3[
    16. requestTime=2023-05-28 14:28:20.629
    17. version=1
    18. ]
    19. 服务器端收到的客户端心跳检测消息: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket@44fd87[
    20. requestTime=2023-05-28 14:28:25.631
    21. version=1
    22. ]
    23. 服务器端收到的客户端心跳检测消息: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket@604ff4[
    24. requestTime=2023-05-28 14:28:30.633
    25. version=1
    26. ]
    27. 服务器端收到的客户端心跳检测消息: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket@25e8dd[
    28. requestTime=2023-05-28 14:28:35.634
    29. version=1
    30. ]
    31. 服务器端收到的客户端心跳检测消息: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket@9fd328[
    32. requestTime=2023-05-28 14:28:40.635
    33. version=1
    34. ]
    35. 服务器端收到的客户端心跳检测消息: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket@a1de30[
    36. requestTime=2023-05-28 14:28:45.637
    37. version=1
    38. ]
    39. 服务器端收到的客户端心跳检测消息: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket@12d255d[
    40. requestTime=2023-05-28 14:28:50.638
    41. version=1
    42. ]
    43. 服务器端收到的客户端心跳检测消息: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket@168f248[
    44. requestTime=2023-05-28 14:28:55.639
    45. version=1
    46. ]
    47. 服务器端收到的客户端心跳检测消息: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket@16a0aee[
    48. requestTime=2023-05-28 14:29:00.640
    49. version=1
    50. ]
    51. 服务器端收到的客户端心跳检测消息: org.jy.sso.websocket.stomp.push.netty.chat.system.chatprotocol.request.ChatHeartBeatRequestPacket@174b2fd[
    52. requestTime=2023-05-28 14:29:05.641
    53. version=1
    54. ]

    ================================闲暇检测日志=============================

     服务器端检测到20秒没数据,就会关闭连接通道:

    1. 15:25:19.094 [main] DEBUG io.netty.channel.DefaultChannelId - -Dio.netty.machineId: 00:50:56:ff:fe:c0:00:01 (auto-detected)
    2. 15:25:19.094 [main] DEBUG io.netty.util.internal.ThreadLocalRandom - -Dio.netty.initialSeedUniquifier: 0x8553a5744ebfc459
    3. 15:25:19.109 [main] DEBUG io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.level: simple
    4. 15:25:19.109 [main] DEBUG io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.maxRecords: 4
    5. 15:25:19.140 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numHeapArenas: 2
    6. 15:25:19.140 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numDirectArenas: 2
    7. 15:25:19.140 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.pageSize: 8192
    8. 15:25:19.140 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxOrder: 11
    9. 15:25:19.140 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.chunkSize: 16777216
    10. 15:25:19.140 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.tinyCacheSize: 512
    11. 15:25:19.140 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.smallCacheSize: 256
    12. 15:25:19.140 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.normalCacheSize: 64
    13. 15:25:19.140 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxCachedBufferCapacity: 32768
    14. 15:25:19.140 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.cacheTrimInterval: 8192
    15. 15:25:19.156 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.allocator.type: pooled
    16. 15:25:19.156 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.threadLocalDirectBufferSize: 65536
    17. 15:25:19.156 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.maxThreadLocalCharBufferSize: 16384
    18. 15:25:46.335 [nioEventLoopGroup-3-1] INFO org.jy.sso.websocket.stomp.push.netty.chat.system.chathandler.ChatIMIdleStateHandler - 20 秒内未读到数据,关闭连接

    客户端再向服务器端发送消息:则通道已经关闭,无法发送

    1. 15:25:26.257 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numHeapArenas: 2
    2. 15:25:26.257 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numDirectArenas: 2
    3. 15:25:26.257 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.pageSize: 8192
    4. 15:25:26.257 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxOrder: 11
    5. 15:25:26.257 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.chunkSize: 16777216
    6. 15:25:26.257 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.tinyCacheSize: 512
    7. 15:25:26.257 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.smallCacheSize: 256
    8. 15:25:26.257 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.normalCacheSize: 64
    9. 15:25:26.257 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxCachedBufferCapacity: 32768
    10. 15:25:26.257 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.cacheTrimInterval: 8192
    11. 15:25:26.271 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.allocator.type: pooled
    12. 15:25:26.272 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.threadLocalDirectBufferSize: 65536
    13. 15:25:26.272 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.maxThreadLocalCharBufferSize: 16384
    14. 2023-05-28 15:25:26.321 -->> 连接成功....
    15. 输入发送到服务器端内容:
    16. 15:25:46.355 [nioEventLoopGroup-2-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxCapacityPerThread: 32768
    17. 15:25:46.355 [nioEventLoopGroup-2-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxSharedCapacityFactor: 2
    18. 15:25:46.355 [nioEventLoopGroup-2-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.linkCapacity: 16
    19. 15:25:46.355 [nioEventLoopGroup-2-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.ratio: 8
    20. 15:25:46.373 [nioEventLoopGroup-2-1] DEBUG io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.bytebuf.checkAccessible: true
    21. 15:25:46.376 [nioEventLoopGroup-2-1] DEBUG io.netty.util.ResourceLeakDetectorFactory - Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector@f95dbb
    22. 4332432432222222222222222222222222222222222
    23. [当前通道已经关闭:]ChatCenterClient.startConsoleTask channel isOpen: false, isActive: false
    24. 输入发送到服务器端内容:

  • 相关阅读:
    外包干了2年,技术退步明显
    coco.py文件详解
    JetBrains 产品安装插件(plugins)的两种方式
    docker安装配置elasticsearch,kibana和IK分词器
    SpringMVC学习笔记(十一)—— 拦截器
    Vue基础(干货+代码)
    请求代理转发(三)
    万字详细总结 Promise(期约)及其方法
    PIE-engine 教程 ——提取黄河流域/山西省1980—2018年流域降水量并对比分析
    分类预测 | MATLAB实现WOA-CNN-GRU-Attention数据分类预测
  • 原文地址:https://blog.csdn.net/u014635374/article/details/130906638