netty client 了解

本文介绍了Netty中的Server和Client服务概念,强调Client必须绑定在Server上进行通信,不能直接相互通信。Netty基于事件机制工作,当客户端与服务端建立连接后,触发相关事件进行处理。本文作为客户端简介的起点,提到了ConnectorIdleStateTrigger。

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

既然是分布式的,自然要分多个服务。Netty中,需要区分Server和Client服务。所有的Client都是绑定在Server上的,他们之间是不能通过Netty直接通信的。(自己采用的其他手段,不包括在内。)。白话一下这个通信过程,Server端开放端口,供Client连接,Client发起请求,连接到Server指定的端口,完成绑定。随后便可自由通信。其实就是普通Socket连接通信的过程。

Netty框架是基于事件机制的,简单说,就是发生什么事,就找相关处理方法。就跟着火了找119,抢劫了找110一个道理。所以,这里,我们处理的是当客户端和服务端完成连接以后的这个事件。什么时候完成的连接,Netty知道,他告诉我了,我就负责处理。这就是框架的作用。Netty,提供的事件还有很多,以后会慢慢的接触和介绍。


客户端简介,参考


首先是ConnectorIdleStateTrigger:

@ChannelHandler.Sharable  
public class ConnectorIdleStateTrigger extends ChannelInboundHandlerAdapter {  
  
    private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Heartbeat",   CharsetUtil.UTF_8));  
  
    @Override  
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {  
        if (evt instanceof IdleStateEvent) {  
            IdleState state = ((IdleStateEvent) evt).state();  
            if (state == IdleState.WRITER_IDLE) {  
                // write heartbeat to server  
                ctx.writeAndFlush(HEARTBEAT_SEQUENCE.duplicate());  
            }  
        } else {  
            super.userEventTriggered(ctx, evt);  
        }  
    }  
}  
简单的自定义的 heartBeatClientHandler
@ChannelHandler.Sharable  
public class HeartBeatClientHandler extends ChannelInboundHandlerAdapter {  
  
    @Override  
    public void channelActive(ChannelHandlerContext ctx) throws Exception {  
        System.out.println("激活时间是:" + new Date());  
        System.out.println("HeartBeatClientHandler channelActive");  
        ctx.fireChannelActive();  
    }  
  
    @Override  
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {  
        System.out.println("停止时间是:" + new Date());  
        System.out.println("HeartBeatClientHandler channelInactive");  
    }  
  
    @Override  
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  
        String message = (String) msg;  
        System.out.println(message);  
        if (message.equals("Heartbeat")) {  
            ctx.write("has read message from server");  
            ctx.flush();  
        }  
        ReferenceCountUtil.release(msg);  
    }  
}  
 接下来就是重点,客户端需要定义一个类,这个类可以去观察链路是否断了,如果断了,进行循环的断线重连操作, ConnectionWatchdog ,顾名思义,链路检测狗,先看完整代码:
@ChannelHandler.Sharable  
public abstract class ConnectionWatchdog extends ChannelInboundHandlerAdapter implements TimerTask, ChannelHandlerHolder {  
  
    private final Bootstrap bootstrap;  
    private final Timer timer;  
    private final int port;  
  
    private final String host;  
  
    private volatile boolean reconnect = true;  
    private int attempts;  
  
    public ConnectionWatchdog(Bootstrap bootstrap, Timer timer, int port, String host, boolean reconnect) {  
        this.bootstrap = bootstrap;  
        this.timer = timer;  
        this.port = port;  
        this.host = host;  
        this.reconnect = reconnect;  
    }  
  
    /** 
     * channel链路每次active的时候,将其连接的次数重新置0 
     */  
    @Override  
    public void channelActive(ChannelHandlerContext ctx) throws Exception {  
        System.out.println("当前链路已经激活了,重连尝试次数重新置为0");  
        attempts = 0;  
        ctx.fireChannelActive();  
    }  
  
    @Override  
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {  
        System.out.println("链接关闭");  
        if (reconnect) {  
            System.out.println("链接关闭,将进行重连");  
            if (attempts < 12) {  
                attempts++;  
            }           //重连的间隔时间会越来越长  
            int timeout = 2 << attempts;  
            timer.newTimeout(this, timeout, TimeUnit.MILLISECONDS);  
        }  
        ctx.fireChannelInactive();  
    }  
  
    @Override  
    public void run(Timeout timeout) throws Exception {  
        ChannelFuture future;  
        //bootstrap已经初始化好了,只需要将handler填入就可以了  
        synchronized (bootstrap) {  
            bootstrap.handler(new ChannelInitializer<Channel>() {  
                @Override  
                protected void initChannel(Channel ch) throws Exception {  
                    ch.pipeline().addLast(handlers());  
                }  
            });  
            future = bootstrap.connect(host, port);  
        }  
        //future对象  
        future.addListener(new ChannelFutureListener() {  
            public void operationComplete(ChannelFuture f) throws Exception {  
                boolean succeed = f.isSuccess();  
               //如果重连失败,则调用ChannelInactive方法,再次出发重连事件,一直尝试12次,如果失败则不再重连  
                if (!succeed) {  
                    System.out.println("重连失败");  
                    f.channel().pipeline().fireChannelInactive();  
                } else {  
                    System.out.println("重连成功");  
                }  
            }  
        });  
    }  
}  
   ConnectionWatchdog继承了ChannelInboundHandlerAdapter,说明它也是Handler;
       实现了2个接口,TimeTask,ChannelHandlerHolder,TimeTask就要重写run方法,这应该是一个定时任务,这个定时任务做的事情应该是重连的工作;ChannelHandlerHolder的接口,这个接口维护的所有的Handlers,因为在重连的时候需要获取Handlers;
       bootstrap对象,重连的时候依旧需要这个对象;
       当链路断开的时候会触发channelInactive这个方法,也就说触发重连的导火索是从这边开始的。

       接下来就是 客户端的Bootstrap:
public class HeartBeatsClient {  
    protected final HashedWheelTimer timer = new HashedWheelTimer();  
  
    private Bootstrap boot;  
  
    private final ConnectorIdleStateTrigger idleStateTrigger = new ConnectorIdleStateTrigger();  
  
    public void connect(int port, String host) throws Exception {  
        EventLoopGroup group = new NioEventLoopGroup();  
        boot = new Bootstrap();  
        boot.group(group)  
                .channel(NioSocketChannel.class)  
                .handler(new LoggingHandler(LogLevel.INFO));  
  
       final ConnectionWatchdog watchdog = new ConnectionWatchdog(boot, timer, port, host, true)     {  
            public ChannelHandler[] handlers() {  
                return new ChannelHandler[]{  
                        this,  
                        new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS),  
                        idleStateTrigger,  
                        new StringDecoder(),  
                        new StringEncoder(),  
                        new HeartBeatClientHandler()  
                };  
            }  
        };  
  
        ChannelFuture future;  
        try {  
            synchronized (boot) {//进行连接  
                boot.handler(new ChannelInitializer<Channel>() {  
                    //初始化channel  
                    @Override  
                    protected void initChannel(Channel ch) throws Exception {  
                        ch.pipeline().addLast(watchdog.handlers());  
                    }  
                });  
                future = boot.connect(host, port);  
            }  
  
            // 以下代码在synchronized同步块外面是安全的  
            future.sync();  
        } catch (Throwable t) {  
            throw new Exception("connects to  fails", t);  
        }  
    }  
  
    public static void main(String[] args) throws Exception {  
        int port = 8000;  
        new HeartBeatsClient().connect(port, "127.0.0.1");  
    }  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值