组件类型
通常分为Client和Server两个,其中如果作为Client通常只需要一个EventLoopGroup并且是用Bootrap绑定该EventLoopGroup用作客户端去监听服务器端的ip和端口。而Server通常是用ServerBootrap绑定两个EventLoopGroup,一个用作连接一个用作处理事务
- EventLoopGroup:管理EventLoop
- EventLoop:处理多个Channel事件
- Channel:代表一个网络连接(有多个ip连接就有多个channel)
- Pipeline:处理
Channel
的数据流 - Handler:用于处理网络事件,如数据读取、写入、连接建立,例如编解码、发送接收数据、心跳检测、加密解密等等
流程与启动执行顺序
通常是先设定一个EventLoopGroup,再设定Bootrap绑定该EventLoopGroup,其中可以通过intiChannel方法设定一些Handler实现一些逻辑。
this.bootstrap.group(this.group).channel(NioSocketChannel.class).handler(new ChannelInitializer<NioSocketChannel>() {@Overrideprotected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {nioSocketChannel.pipeline().addLast(new ByteArrayEncoder(), // 发送字节数据 使用原始的ByteBuf进行传输new PrinterStatusHandler());}});
当有ip与Bootrap进行连接的时候(调用Bootstrap.connect()方法),EventLoopGroup会选取一个EventLoop
就来绑定这一个线程,负责处理一个或多个 Channel
的事件,并且分配一个Channel绑定在该EventLoop上
去处理这个ip进行通信(注意:每次调用 Bootstrap.connect()
都会创建一个新的 Channel,如果是同一个ip再去调用connect()方法是会新建Channel去连接这个ip导致Channel重复被创建取消,这没有被复用到,通常来说只要不主动断开连接或者调用close()方法Channel都会与其一直进行连接),然后每个Channel里包含pipeline,里面都会经历过所有Handler来进行对应逻辑处理。
同时给一个个人的小建议:通常来说都会独立编写connect()和send()两个操作,要记得保证connect()先正常连接再调用send()如下:
public void connect(){ChannelFuture future = this.bootstrap.connect(ip, Integer.parseInt(port));// 避免同步连接阻塞future.addListener((ChannelFutureListener) f -> {if (f.isSuccess()) {System.out.println("成功连接到ip为:"+ip+port+"");log.info("成功连接到ip为:{}:{}" ,ip ,port);channel = f.channel();} else {log.error("连接到ip为:{}:{}失败" ,ip ,port);}});// 监听当前channel的关闭事件future.channel().closeFuture().addListener((ChannelFutureListener) f -> {log.info("打印机已关闭");statusCallback.put(statusKey , PrinterStatus.FAULT);System.out.println("已关闭");// 延迟 5 秒后重新连接if(retryConnectCount.get() > 0){log.info("正在重新尝试连接");f.channel().eventLoop().schedule(this::connect, 3, TimeUnit.SECONDS);retryConnectCount.decrementAndGet();}else {retryConnectCount.set(3);log.error("重新尝试连接");}});}
public void send(){//等待异步的channel被设置好sleep(1000);if(channel != null && channel.isActive()){channel.writeAndFlush(new byte[]{0x10, 0x04, 0x01});}else{System.out.println("当前Channel已失活");}}