IM心跳机制

252 阅读2分钟

im心跳两种方式

客户端心跳机制

  • 客户端定时ws通知服务端,服务端响应客户端
  • 服务端通过netty的组件IdleStateHandler设置读超时空闲时间和写空闲时间

前提是客户端心跳间隔小于服务端读空闲时间;

当监听到读空闲时间,说明客户端没有在指定的时间心跳通知,可能存在断线或者网络问题,记录超时次数,达到上限,服务端进行离线处理。

服务端心跳机制

  • 客户端建立ws连接
  • 服务端通过netty的组件IdleStateHandler设置读超时空闲时间和写空闲时间
  • 收到写超时事件发送一个ping事件通知给客户端
  • 客户端响应pong事件

如果客户端没有响应pong(离线、网络差),服务端连续ping三次后,认定客户端不在线,进行离线处理。

sprinboot项目启动后创建一个websocket站点

public void start() {
    ServerBootstrap bootstrap = new ServerBootstrap();
    bossGroup = new NioEventLoopGroup();
    workGroup = new NioEventLoopGroup();
    // 设置为主从线程模型
    bootstrap.group(bossGroup, workGroup)
            // 设置服务端NIO通信类型
            .channel(NioServerSocketChannel.class)
            // 设置ChannelPipeline,也就是业务职责链,由处理的Handler串联而成,由从线程池处理
            .childHandler(new ChannelInitializer<Channel>() {
                // 添加处理的Handler,通常包括消息编解码、业务处理,也可以是日志、权限、过滤等
                @Override
                protected void initChannel(Channel ch) {
                    // 获取职责链
                    ChannelPipeline pipeline = ch.pipeline();
                    pipeline.addLast(new IdleStateHandler(10, 15, 0, TimeUnit.SECONDS));
                    pipeline.addLast("http-codec", new HttpServerCodec());
                    pipeline.addLast("aggregator", new HttpObjectAggregator(65535));
                    pipeline.addLast("http-chunked", new ChunkedWriteHandler());
                    pipeline.addLast(new WebSocketServerProtocolHandler("/im"));
                    pipeline.addLast("encode", new MessageProtocolEncoder());
                    pipeline.addLast("decode", new MessageProtocolDecoder());
                    pipeline.addLast("handler", new IMChannelHandler());
                }
            })
            // bootstrap 还可以设置TCP参数,根据需要可以分别设置主线程池和从线程池参数,来优化服务端性能。
            // 其中主线程池使用option方法来设置,从线程池使用childOption方法设置。
            // backlog表示主线程池中在套接口排队的最大数量,队列由未连接队列(三次握手未完成的)和已连接队列
            .option(ChannelOption.SO_BACKLOG, 5)
            // 表示连接保活,相当于心跳机制,默认为7200s
            .childOption(ChannelOption.SO_KEEPALIVE, true);

    try {
        // 绑定端口,启动select线程,轮询监听channel事件,监听到事件之后就会交给从线程池处理
        bootstrap.bind(port).sync().channel();
        // 就绪标志
        this.ready = true;
        log.info("websocket server 初始化完成,端口:{}", port);
        // 等待服务端口关闭
        //channel.closeFuture().sync();
    } catch (InterruptedException e) {
        log.info("websocket server 初始化异常", e);
    }
}

IdleStateEvent 有三个状态:

  • READER_IDLE:表示从上一次读取数据以来已经过去了指定的时间,但没有数据被读取。
  • WRITER_IDLE:表示从上一次写入数据以来已经过去了指定的时间,但没有数据被写入。
  • ALL_IDLE:表示从上一次读取或写入数据以来,两者都已经过去了指定的时间。