netty以及心跳检测demo

这篇博客详细介绍了如何使用Netty实现心跳检测机制。通过一个简单的demo,包括Client和Server端的Java代码,展示了从连接建立到心跳检测的过程。在Client端,当连接激活时,发送特定key到Server,Server接收到key后回应。Client接收到回应后,通过线程池定时发送消息。Server端接收到非key信息时,会回传给Client,客户端根据接收的数据判断并作出相应处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在学习netty,做一个netty的小demo吧

PS(本片博客参考了白贺翔老师的netty视频教程)

 

pom文件

  <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>5.0.0.Alpha2</version>
  </dependency>

Client客户端 HeatBeatClient.java

package com.function.netty.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;


public class HeatBeatClient {

    private static Channel channel;
    private static EventLoopGroup group;

    public static void main(String[] args) {
        initclient();
    }

    public static void initclient(){
        group = new NioEventLoopGroup();
        Bootstrap b = new Bootstrap();
        b.group(group).channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline()
                                .addLast(new ObjectEncoder())
                                .addLast(new ObjectDecoder(ClassResolvers.weakCachingResolver(null)))
                                .addLast(new HeartBeatClientHandler());
                    }
                });

        try {
            channel = b.connect("127.0.0.1",6789).sync().channel();
            channel.closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            group.shutdownGracefully();
        }
    }

}

 

 Server端 HeartBeatServer.java

package com.function.netty.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;


public class HeartBeatServer {

    public static void main(String[] args) {

        EventLoopGroup pGroup = new NioEventLoopGroup();
        EventLoopGroup cGroup = new NioEventLoopGroup();

        ServerBootstrap b = new ServerBootstrap();
        b.group(pGroup,cGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline()
                                .addLast(new ObjectEncoder())
                                .addLast(new ObjectDecoder(ClassResolvers.weakCachingResolver(null)))
                                .addLast(new HeatBeatServerHandler());
                    }
                });

        try {
            Channel channel = b.bind("127.0.0.1",6789).sync().channel();
            channel.closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        pGroup.shutdownGracefully();
        cGroup.shutdownGracefully();
    }
}

 

测试功能时启动这两个main函数即可。但是还需要server和client两个handler

client端处理逻辑 HeartBeatClientHandler.java

package com.function.netty.client;

import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class HeartBeatClientHandler extends ChannelHandlerAdapter{

    private ScheduledExecutorService sch = Executors.newScheduledThreadPool(1);
    private ScheduledFuture<?> future;
    private String keyWord = "KEY_SUCCESS";

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String message = (String) msg;
        if(message.equals(keyWord)) {
            this.future = this.sch.scheduleWithFixedDelay(new ScheduledExecutorThread(ctx), 2, 2, TimeUnit.SECONDS);
        }else{
            System.out.println(message);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("正在连接"+ctx.channel().remoteAddress());
        ctx.writeAndFlush(keyWord);
    }

    /**
     * @Description: 当Netty由于IO错误或者处理器在处理事件时抛出异常时调用
     * @Date: 2018/12/18  15:21
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        ctx.close();
    }

    private class ScheduledExecutorThread implements Runnable{
        private final ChannelHandlerContext ctx;
        ScheduledExecutorThread(final ChannelHandlerContext ctx){
            this.ctx = ctx;
        }
        @Override
        public void run() {
            ctx.writeAndFlush("客户端普通消息");
        }
    }
}


 server端处理逻辑HeatBeatServerHandler.java

package com.function.netty.server;

import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;


public class HeatBeatServerHandler extends ChannelHandlerAdapter{

    private String keyword = "KEY_SUCCESS";

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String message = (String) msg;

        if(message.equals(keyword)){
            System.out.println(message);
            ctx.writeAndFlush(keyword);
        }else{
            System.out.println(message);
            ctx.writeAndFlush("服务端普通消息");
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("建立连接的客户端地址是"+ctx.channel().remoteAddress());
    }
}

至此代码已全部粘贴,具体流程是这样的:

1、先启动server端,再启动client端。

2、启动client之后连两端建立连接,触发了HeartBeatClientHandler中的channelActive方法,然后发送key到服务端,服务端接收信息方法中会判断是否为key,是就返回客户端key,否就返回普通字符串。

3、客户端的channelRead方法接收到了key,开启线程池,

this.future = this.sch.scheduleWithFixedDelay(new ScheduledExecutorThread(ctx), 2, 2, TimeUnit.SECONDS);
两秒钟之后每两秒执行一次。

我们看一下scheduleWithFixedDelay()这个方法,第一个参数就是Runnable

定义了一个内部类 ScheduledExecutorThread 实现Runnable接口,重写run方法,利用传入的ChannelHandlerContext 去往服务端写一句话ctx.writeAndFlush("客户端普通消息")。

4、服务端channelRead方法接收到信息,并不是key就直接输出到控制台并且再写回客户端,客户端这时接收到数据判断不是key输出到控制台就不处理了,因为有线程已经在跑了。

5、看起来很绕,其实很简单的处理,接下来看控制台。

server端:

客户端:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值