当前位置:   article > 正文

Spring boot的基础总结(五)-------Netty->websocker+心跳检测_springboot+netty 心跳检测

springboot+netty 心跳检测

咱们的学习思路比较奇特,看到啥学啥。
先将为什么要用Websocker.因为Http只能由客户端发送给服务端。而没办法相互通信,而Websocker解决了这个问题。
那Spring boot有自带的WebSocker集成,那为啥不用呢?因为Netty比较牛逼(建议自行百度)。本人理解就是,它可以变成所有的协议服务,用自定义的操作很方便又简易的开发方式,Netty成功地找到了一种在不妥协的情况下实现易于开发,性能,稳定性和灵活性的方法。
这里只做服务器的代码,客户端的测试,可以去找一下测试工具!!!

你可以偷偷用,不要告诉别人喔~
好,然后到了我们的实现步骤,

1.添加依赖

<dependency>
   <groupId>io.netty</groupId>
   <artifactId>netty-all</artifactId>
   <version>4.1.21.Final</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

2.构造Netty服务初始器


/**
 * @author
 *
 * netty服务初始化器
 * 主要是配置业务的前置信息
 * 比如像和客户端通信,指定相应的通信协议,编码解码信息,自定义相关的handler
 **/
public class NettyServerChannelInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        //添加编解码
        socketChannel.pipeline().addLast(new HttpServerCodec());
        //添加对于读写大数据流的支持
        socketChannel.pipeline().addLast(new ChunkedWriteHandler());
        //对httpMessage进行聚合
        socketChannel.pipeline().addLast(new HttpObjectAggregator(1024*64));
        // WebSocketServerProtocolHandler:将 http 协议升级为 ws 协议,保持长连接
        socketChannel.pipeline().addLast(new WebSocketServerProtocolHandler("/ws"));
        // 增加IdleStateHandler心跳检测处理器,userEventTriggered()方法作为超时事件,如果五秒内ChannelRead()方法未被调用
        socketChannel.pipeline().addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));
        //增加一个自己的Handler操作
        socketChannel.pipeline().addLast(new NettyServerHandler());

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

可以在代码看到,里面添加了很多类进去,注意倒数三个,一个是将http变成Websock,一个是心跳检测器,是哪个参数分别对应,客户端的写操作超时时间,读操作超时时间,全部操作超时时间,第三个是我们自定义的业务Handler。埋个伏笔(关于编解码的问题,只知道概念,不知道会有什么影响…)

3.新建Handler类


/**
 * @author
 *
 * WebSocketFrame: 表示一个文本帧
 * netty服务端处理器
 **/

public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);

    /**
     * 客户端连接会触发
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        logger.info("Channel active......");
    }

    /**
     * 客户端发消息会触发
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        logger.info("服务器收到消息: {}", msg.toString());
        if (msg instanceof TextWebSocketFrame) {
            TextWebSocketFrame textMsg = (TextWebSocketFrame) msg;
            logger.info("服务器收到文本消息: {}", textMsg.text());

        }

        //ctx.channel().write(new TextWebSocketFrame("abc"));

        ctx.flush();
    }

    /**
     * 发生异常触发
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    //客户端销毁的时候触发,
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        //当handlerRemoved 被触发时候,channelGroup会自动移除对应的channel
        //clients.remove(ctx.channel());
        System.out.println("客户端断开,当前被移除的channel的短ID是:" + ctx.channel().id().asShortText());
    }

    private int lossConnectCount = 0;
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception {
        if (obj instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) obj;
            //这就是客户端不写过来
            if (event.state() == IdleState.READER_IDLE) {
                logger.info("客户端写超时");
                lossConnectCount++;
                if(lossConnectCount > 2){
                    logger.info("关闭这个不活跃的通道");
                    ctx.channel().close();
                }
                //这是客户端不读
            } else if (event.state() == IdleState.WRITER_IDLE) {
                logger.info("客户端读超时");
                //如果都没操作就都无
            } else if (event.state() == IdleState.ALL_IDLE) {
                logger.info("客户端所有操作超时");
            }
        }
        }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

重点都在注释里面了。。我就不讲解了

4.设置服务并且开启

新建NettyServer类


/**
 * @author
 * <p>
 * 服务启动监听器
 **/
public class NettyServer {
    private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);

    public void start(InetSocketAddress socketAddress) {
        //new 一个主线程组
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        //new 一个工作线程组
        EventLoopGroup workGroup = new NioEventLoopGroup(200);
        ServerBootstrap bootstrap = new ServerBootstrap()
                .group(bossGroup, workGroup)
                //设置通道
                .channel(NioServerSocketChannel.class)
                //设置子处理器
                .childHandler(new NettyServerChannelInitializer())
                .localAddress(socketAddress)
                //设置队列大小
                .option(ChannelOption.SO_BACKLOG, 1024)
                // 两小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文
                .childOption(ChannelOption.SO_KEEPALIVE, true);
        //绑定端口,开始接收进来的连接
        try {
            ChannelFuture future = bootstrap.bind(socketAddress).sync();
            logger.info("服务器启动开始监听端口: {}", socketAddress.getPort());
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //关闭主线程组
            bossGroup.shutdownGracefully();
            //关闭工作线程组
            workGroup.shutdownGracefully();
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

在启动类里面加入这个方法


    public static void main(String[] args) {

        SpringApplication.run(DevApplication.class, args);

        //1.判断库是否存在
        //2.建库.
        //3.判断表是否存在,不存在建立表,存在则更新数据库表结构
        //4.表建立完之后,进行外键的连接。

        //启动服务端
        NettyServer nettyServer = new NettyServer();
        nettyServer.start(new InetSocketAddress("172.31.97.13", 6088));
    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

我们来看看结果
在这里插入图片描述
Nice,Bro
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/242112
推荐阅读
相关标签
  

闽ICP备14008679号