netty入门-3 EventLoop和EventLoopGroup,简单的服务器实现
创始人
2024-12-21 07:05:38
0

文章目录

  • EventLoop和EventLoopGroup
    • 服务器与客户端基本使用
    • 增加非NIO工人
    • NioEventLoop 处理普通任务与定时任务
  • 结语

EventLoop和EventLoopGroup

二者大概是什么这里不再赘述,前一篇已简述过。
不理解也没关系。
下面会简单使用,看了就能明白是什么
这篇文章只说NioEventLoopGroup
后续文章会有服务器创建类BootStrap的方法总结。

服务器与客户端基本使用

EventLoopGroup的常用实现类是NioEventLoopGroup
就以此为例,我们来看这两者,在使用netty创建一个服务器的过程中处于什么位置。

PS:我觉得既然是专注于这个东西怎么用,就不要太纠结于底层。
我当时看到childHandler,就想弄明白这个到底是怎么把Handler加到新ChannelPipeline中的。这就要涉及源码。下面这个链式调用其他部分也是一样。想搞明白每个调用的底层还是需要看源码。会给初学者带来没必要的精力耗费。我觉得需要收住好奇心,先会简单使用,再说底层实现。

//服务端 //ServerBootstrap相当于提供了创建服务器的辅助类。允许通过链式调用更优雅的启动一个服务器。 //我们通过一系列链式调用完成了服务器的创建。 new ServerBootstrap() 	//group相当于我们配置EventLoopGroup的地方,它将用于后续的事件处理    .group(new NioEventLoopGroup(1), new NioEventLoopGroup(2))    //channel指定通道类型,NioServerSocketChannel是netty的封装类,即NIO中的升级版    .channel(NioServerSocketChannel.class)    //这个名字child代表子通道,什么意思?即我们有一个NioServerSocketChannel来处理Accept请求。接受的每个连接都会创建自己的SocketChannel用于通信,可当作child,即子通道。    //所以顾名思义子通道处理器。即为新创建的每一个子通道都会绑定这个ChannelInitializer,那么它又是做什么的?    //ChannelInitializer会在每个新Channel被注册到EventLoopGroup时执行内部我们重写的initChannel方法,将我们在initChannel方法中自定义的处理器添加到我们这个channel的channelpipeline中。即为我们新连接的Channel添加一个handler。关于handler和pipeline,在上篇中简单讲述了是什么。    //简单来说,它是对每个新建立的连接Channel,指定我们写好的处理逻辑,之后Channel的读写操作都会经过这些逻辑。    .childHandler(new ChannelInitializer() {        @Override        protected void initChannel(NioSocketChannel ch) {//这里的参数我猜测就是我们新连接的channel        //这里对新channel添加我们自定义的handler            ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {                @Override                public void channelRead(ChannelHandlerContext ctx, Object msg) {                    ByteBuf byteBuf = msg instanceof ByteBuf ? ((ByteBuf) msg) : null;                    if (byteBuf != null) {                        byte[] buf = new byte[16];                        ByteBuf len = byteBuf.readBytes(buf, 0, byteBuf.readableBytes());                        log.debug(new String(buf));                    }                }            });        }        //绑定端口,并sync阻塞住    }).bind(8080).sync(); 

这里还有一些理解
channel()方法,将我们指定的NioServerSocketChannel注册到group中的第一个group内的某个EventLoop,由该EventLoop监听。第一个group中的EventLoop被称为Boss,专门处理连接请求。
所有连接由NioServerSocketChannel处理,同时新连接产生的SocketChannel注册到第二个group内的某个EventLoop,由该EventLoop监听。这些EventLoop被称为Worker。处理读写请求。
上面程序中相当于有两个Worker,因为创建EventLoopGroup时参数为2。

所以小结一下。每个Channel都会由一个EventLoop监听。并且在事件发生时调用对应的处理器进行处理。即完成对事件的监听和处理。

//客户端 //通过链式调用,拿到连接完毕的Channel Channel channel = new Bootstrap()             .group(new NioEventLoopGroup(1))             .handler(new ChannelInitializer() {                 @Override                 protected void initChannel(NioSocketChannel ch) throws Exception {                     System.out.println("init...");                     ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));                 }             })             .channel(NioSocketChannel.class).connect("localhost", 8080)             .sync()             .channel();  // 发送消息 channel.writeAndFlush(ByteBufAllocator.DEFAULT.buffer().writeBytes("wangwu".getBytes()));     Thread.sleep(2000);     channel.writeAndFlush(ByteBufAllocator.DEFAULT.buffer().writeBytes("wangwu".getBytes())); 

这里多创建几个客户端发消息,会发现服务器中的两个Worker会分别处理属于自己管理Channel的事件。

增加非NIO工人

下面程序有两个handler
LoggingHandler"myhandler"
引入了一个我们自己创建的DefaultEventLoopGroup 去处理"myhandler"的任务,即非NIO工人

//额外的工程组 //非NIO工人2个 DefaultEventLoopGroup normalWorkers = new DefaultEventLoopGroup(2); new ServerBootstrap()     .group(new NioEventLoopGroup(1), new NioEventLoopGroup(2))     .channel(NioServerSocketChannel.class)     .childHandler(new ChannelInitializer() {         @Override         protected void initChannel(NioSocketChannel ch)  {             ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));             ch.pipeline().addLast(normalWorkers,"myhandler",               new ChannelInboundHandlerAdapter() {                 @Override                 public void channelRead(ChannelHandlerContext ctx, Object msg) {                     ByteBuf byteBuf = msg instanceof ByteBuf ? ((ByteBuf) msg) : null;                     if (byteBuf != null) {                         byte[] buf = new byte[16];                         ByteBuf len = byteBuf.readBytes(buf, 0, byteBuf.readableBytes());                         log.debug(new String(buf));                     }                 }             });         }     }).bind(8080).sync(); 

看完这个代码,我们看添加handler时的参数,我们发现"myhandler"被交给了我们自己一开始创建的DefaultEventLoopGroup normalWorkers 来执行。
关系见下图
headtail看做pipelinehandler链的头尾,可视为无意义。
h1代表LoggingHandler
h2代表"myhandler"
在这里插入图片描述

那么这里老师巧妙的引出了pipeline处理过程中的handler的切换,因为两个handler分别是两个不同的EventLoop去执行,就需要一个执行完后交给另一个EventLoop去执行。然后引出了源码,比较容易让人接受,理解。

//handler换人源码 static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {     final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);     // 下一个 handler 的事件循环是否与当前的事件循环是同一个线程     EventExecutor executor = next.executor();          // 是,直接调用     if (executor.inEventLoop()) {         next.invokeChannelRead(m);     }      // 不是,将要执行的代码作为任务提交给下一个事件循环处理(换人)     else {         executor.execute(new Runnable() {             @Override             public void run() {                 next.invokeChannelRead(m);             }         });     } } 
  • 如果两个 handler 绑定的是同一个线程(EventLoop),那么就直接调用
  • 否则,把要调用的代码封装为一个任务对象,由下一个 handler 的线程来调用

NioEventLoop 处理普通任务与定时任务

NioEventLoop还可以执行普通任务和定时任务

//普通任务 NioEventLoopGroup nioWorkers = new NioEventLoopGroup(2); log.debug("server start..."); Thread.sleep(2000); nioWorkers.execute(()->{     log.debug("normal task..."); });  //定时任务 NioEventLoopGroup nioWorkers = new NioEventLoopGroup(2); log.debug("server start..."); Thread.sleep(2000); nioWorkers.scheduleAtFixedRate(() -> {     log.debug("running..."); }, 0, 1, TimeUnit.SECONDS);  

结语

仅仅说使用的话内容好像不多。
api使用的话还要之后自己进行网络程序的编写,学习过程中估计很难记住。还是要学完去实践才能熟练使用。
下篇应该是Netty的Future与Promise,或者Netty Channel相比于NIO的有什么不同(这块估计要看下书,课上没咋提)。

后续会有文章单独说明ServerBootstrap类的一些方法。

感谢阅读,欢迎批评指正。

相关内容

热门资讯

德州扑克玩家心理!wpk辅助器... 德州扑克玩家心理!wpk辅助器,wepoke靠谱一直是真的有挂1、下载好wpk辅助器辅助软件之后点击...
6分钟科普!新广西老友麻将十三... 6分钟科普!新广西老友麻将十三张有挂吗,德州本来存在有挂,分享教程(有挂攻略)1、新广西老友麻将十三...
新手必备!吉祥麻将免输神器下载... 新手必备!吉祥麻将免输神器下载(辅助)一贯是有挂(2024已更新)(哔哩哔哩);新手必备!吉祥麻将免...
推荐一款!!博雅红河棋盘外挂(... 推荐一款!!博雅红河棋盘外挂(辅助挂)透视辅助神器(2022已更新)(哔哩哔哩);所有人都在同一条线...
心理战术训练!wepoke模拟... 心理战术训练!wepoke模拟器,wepooke系统规律软件透明挂1、这是跨平台的wepoke模拟器...
传递经验!阳光岛牌乐汇麻将有挂... 传递经验!阳光岛牌乐汇麻将有挂吗(透明挂)都是是有挂(2021已更新)(哔哩哔哩)1、全新机制【阳光...
1分钟实锤!jj斗地主小程序有... 1分钟实锤!jj斗地主小程序有挂吗,AAPOKEr都是真的是有挂,玩家教你(有挂黑科技);一、jj斗...
实操分享!填大坑智能辅助(透视... 实操分享!填大坑智能辅助(透视)外挂透明挂辅助软件(2025已更新)(哔哩哔哩)1、点击下载安装,填...
科普!吉祥填大坑开发软件(辅助... 科普!吉祥填大坑开发软件(辅助挂)果然存在有挂(2022已更新)(哔哩哔哩)1、下载好吉祥填大坑开发...
逻辑思维游戏!微扑克ai辅助,... 您好,微扑克ai辅助这款游戏可以开挂的,确实是有挂的,需要了解加微【136704302】很多玩家在这...