netty编程实战02-创建一个带有连接重试的tcp客户端程序

简介: netty编程实战02-创建一个带有连接重试的tcp客户端程序

netty编程实战01中我们写了一个带有心跳检测的tcp服务端程序,这次我们就写一个带有连接重试功能的tcp客户端程序,话不多说上代码:

tcp客户端

/**
 * 带有连接重试的tcp客户端
 */
@Slf4j
public class NettyClient {
    // 心跳发送包,使用unreleasableBuffer避免重复创建对象
    public static final ByteBuf HEART_BUF = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("ping", CharsetUtil.UTF_8));
    public static void main(String[] args) {
        // 创建客户端启动器
        Bootstrap bootstrap = new Bootstrap();
        NioEventLoopGroup group = new NioEventLoopGroup();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<Channel>() {
                    @Override
                    protected void initChannel(Channel ch) {
                        // 创建一个心跳检测的handle,客户端创建连接后,3秒内没有收到服务端的心跳就会触发IdleState.WRITER_IDLE
                        ch.pipeline().addLast("idleStateHandler", new IdleStateHandler(0, 3, 0));
                        // 使用双向处理器,发送ping消息给服务端
                        ch.pipeline().addLast(new ChannelDuplexHandler() {
                            // 服务端连接关闭时,进行重试操作
                            @Override
                            public void channelInactive(ChannelHandlerContext ctx) {
                                ctx.executor().schedule(() -> NettyClient.connect(bootstrap), 5, TimeUnit.SECONDS);
                            }
                            // 3秒内没有向服务端发送心跳会触发userEventTriggered方法
                            @Override
                            public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
                                if (evt instanceof IdleStateEvent) {
                                    IdleStateEvent e = (IdleStateEvent) evt;
                                    if (e.state() == IdleState.WRITER_IDLE) {
                                        ctx.channel().writeAndFlush(HEART_BUF);
                                    }
                                }
                            }
                            // 发生异常时,关闭连接
                            @Override
                            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
                                log.error(cause.getMessage(), cause);
                                ctx.close();
                            }
                        });
                        // netty日志记录,打印包信息
                        ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
                        // 自定义解码器,实现自定义业务逻辑,使用ChannelInboundHandlerAdapter时需要手动关闭byteBuf
                        ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                            // 连接建立触发channelActive
                            @Override
                            public void channelActive(ChannelHandlerContext ctx) {
                                ByteBuf buffer = ctx.alloc().buffer();
                                buffer.writeBytes((new Date() + ": hello world!\r\n").getBytes(StandardCharsets.UTF_8));
                                ctx.writeAndFlush(buffer);
                            }
                            // 收到来自服务端的消息
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) {
                                ByteBuf byteBuf = (ByteBuf) msg;
                                try {
                                    log.info(new String(ByteBufUtil.getBytes(byteBuf)));
                                } finally { // 由于使用的是ChannelInboundHandlerAdapter,需要手动释放byteBuf
                                    byteBuf.release();
                                }
                            }
                        });
                    }
                });
        connect(bootstrap);
    }
    /**
     * 连接重试
     *
     * @param bootstrap
     */
    @SneakyThrows
    private static void connect(Bootstrap bootstrap) {
        bootstrap.connect("127.0.0.1", 99).sync().addListener(future -> {
            if (future.isSuccess()) {
                log.info("连接成功!");
            } else {
                Thread.sleep(5000);
                log.info("连接失败,开始重连");
                connect(bootstrap);
            }
        });
    }
}

本地测试

image.png

  1. 21:02:32连接关闭报错
  2. 21:05:39重试失败
  3. 21:05:40重试成功,重新建立连接
目录
相关文章
|
2月前
|
缓存 网络协议 算法
《跟闪电侠学Netty》阅读笔记 - Netty入门程序解析
《跟闪电侠学Netty》阅读笔记 - Netty入门程序解析
134 0
|
2月前
|
Java Unix Linux
【Netty技术专题】「原理分析系列」Netty强大特性之Native transports扩展开发实战
当涉及到网络通信和高性能的Java应用程序时,Netty是一个强大的框架。它提供了许多功能和组件,其中之一是JNI传输。JNI传输是Netty的一个特性,它为特定平台提供了高效的网络传输。 在本文中,我们将深入探讨Netty提供的特定平台的JNI传输功能,分析其优势和适用场景。我们将介绍每个特定平台的JNI传输,并讨论其性能、可靠性和可扩展性。通过了解这些特定平台的JNI传输,您将能够更好地选择和配置适合您应用程序需求的网络传输方式,以实现最佳的性能和可靠性。
57 7
【Netty技术专题】「原理分析系列」Netty强大特性之Native transports扩展开发实战
|
2月前
|
网络协议
Netty实现TCP通信
Netty实现TCP通信
43 0
|
16天前
|
网络协议 Java 物联网
Spring Boot与Netty打造TCP服务端(解决粘包问题)
Spring Boot与Netty打造TCP服务端(解决粘包问题)
26 1
|
30天前
|
NoSQL Redis
Netty实战:模拟Redis的客户端
Netty实战:模拟Redis的客户端
14 0
|
2月前
|
安全 Java Go
springboot+netty化身Udp服务端,go化身客户端模拟设备实现指令联动
springboot+netty化身Udp服务端,go化身客户端模拟设备实现指令联动
70 0
|
3月前
|
前端开发 Java Maven
【Netty 网络通信】启动客户端连接服务端实现通信
【1月更文挑战第9天】【Netty 网络通信】启动客户端连接服务端实现通信
|
3月前
|
Java Maven
Netty | 属于你的第一款Netty应用程序 🚀
Netty | 属于你的第一款Netty应用程序 🚀
40 0
|
3月前
|
分布式计算 前端开发 网络协议
13W字!腾讯高工手写“Netty速成手册”,3天能走向实战
在java界,netty无疑是开发网络应用的拿手菜。你不需要太多关注复杂的nio模型和底层网络的细节,使用其丰富的接口,可以很容易的实现复杂的通讯功能。
|
7月前
|
监控 Java Linux
由浅入深Netty基础知识NIO网络编程1
由浅入深Netty基础知识NIO网络编程
40 0