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

该博客介绍了如何使用Netty构建WebSocket服务器,而非Springboot自带的WebSocket集成。Netty因其高性能和灵活性被选用。详细步骤包括添加依赖、构建Netty服务初始化器、创建自定义Handler以及设置和启动服务器。在Handler中处理客户端连接、消息读取和异常,并实现了心跳检测功能。
摘要由CSDN通过智能技术生成

咱们的学习思路比较奇特,看到啥学啥。
先将为什么要用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>

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());

    }
}

可以在代码看到,里面添加了很多类进去,注意倒数三个,一个是将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("客户端所有操作超时");
            }
        }
        }
}

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

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();
        }
    }
}

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


    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));
    }

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值