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重试成功,重新建立连接
目录
相关文章
|
5月前
|
网络协议 前端开发
netty的TCP服务端和客户端实现
本文介绍了使用Netty框架实现TCP服务端和客户端的步骤,包括添加Netty依赖、编写服务端和客户端的代码,涉及NioEventLoopGroup、ServerBootstrap、Bootstrap、ChannelInitializer等核心组件,以及如何启动服务端监听和客户端连接。
392 4
|
5月前
使用Netty实现文件传输的HTTP服务器和客户端
本文通过详细的代码示例,展示了如何使用Netty框架实现一个文件传输的HTTP服务器和客户端,包括服务端的文件处理和客户端的文件请求与接收。
141 1
使用Netty实现文件传输的HTTP服务器和客户端
|
7月前
|
编解码 NoSQL Redis
(十一)Netty实战篇:基于Netty框架打造一款高性能的IM即时通讯程序
关于Netty网络框架的内容,前面已经讲了两个章节,但总归来说难以真正掌握,毕竟只是对其中一个个组件进行讲解,很难让诸位将其串起来形成一条线,所以本章中则会结合实战案例,对Netty进行更深层次的学习与掌握,实战案例也并不难,一个非常朴素的IM聊天程序。
159 3
|
7月前
|
前端开发 网络协议
Netty实战巅峰:从零构建高性能IM即时通讯系统,解锁并发通信新境界
【8月更文挑战第3天】Netty是一款高性能、异步事件驱动的网络框架,适用于开发高并发网络应用,如即时通讯(IM)系统。本文将指导你利用Netty从零构建高性能IM程序,介绍Netty基础及服务器/客户端设计。服务器端使用`ServerBootstrap`启动,客户端通过`Bootstrap`连接服务器。示例展示了简单的服务器启动过程。通过深入学习,可进一步实现用户认证等功能,打造出更完善的IM系统。
254 1
|
7月前
|
移动开发 网络协议 算法
(十)Netty进阶篇:漫谈网络粘包、半包问题、解码器与长连接、心跳机制实战
在前面关于《Netty入门篇》的文章中,咱们已经初步对Netty这个著名的网络框架有了认知,本章的目的则是承接上文,再对Netty中的一些进阶知识进行阐述,毕竟前面的内容中,仅阐述了一些Netty的核心组件,想要真正掌握Netty框架,对于它我们应该具备更为全面的认知。
321 2
|
8月前
|
安全 NoSQL Java
网络安全-----Redis12的Java客户端----客户端对比12,Jedis介绍,使用简单安全性不足,lettuce(官方默认)是基于Netty,支持同步,异步和响应式,并且线程是安全的,支持R
网络安全-----Redis12的Java客户端----客户端对比12,Jedis介绍,使用简单安全性不足,lettuce(官方默认)是基于Netty,支持同步,异步和响应式,并且线程是安全的,支持R
|
缓存 Java API
Netty是如何断开连接的?
Netty是如何断开连接的?
446 0
Netty是如何断开连接的?
|
存储 缓存 NoSQL
跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)
本文将要分享的是如何从零实现一套基于Netty框架的分布式高可用IM系统,它将支持长连接网关管理、单聊、群聊、聊天记录查询、离线消息存储、消息推送、心跳、分布式唯一ID、红包、消息同步等功能,并且还支持集群部署。
13600 1
|
10月前
|
消息中间件 Oracle Dubbo
Netty 源码共读(一)如何阅读JDK下sun包的源码
Netty 源码共读(一)如何阅读JDK下sun包的源码
189 1
|
NoSQL Java Redis
跟着源码学IM(十二):基于Netty打造一款高性能的IM即时通讯程序
关于Netty网络框架的内容,前面已经讲了两个章节,但总归来说难以真正掌握,毕竟只是对其中一个个组件进行讲解,很难让诸位将其串起来形成一条线,所以本章中则会结合实战案例,对Netty进行更深层次的学习与掌握,实战案例也并不难,一个非常朴素的IM聊天程序。 原本打算做个多人斗地主练习程序,但那需要织入过多的业务逻辑,因此一方面会带来不必要的理解难度,让案例更为复杂化,另一方面代码量也会偏多,所以最终依旧选择实现基本的IM聊天程序,既简单,又能加深对Netty的理解。
201 1