八.Netty入门到超神系列-Netty入门程序

Posted 墨家巨子@俏如来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了八.Netty入门到超神系列-Netty入门程序相关的知识,希望对你有一定的参考价值。

前言

上一章讨论的是Netty的线程模型,这一章我们基于上一章的线程模型来实战一把。由于Netty5出现重大BUG被官方废弃,所以我们使用Netty4进行学习。

Netty入门实战

在开始之前再来分析一下Netty的线程模型
我们需要有NioEventLoopGroup来循环监听请求事件,需要有Handler来处理事件,所以在写代码之前我们先来了解几个类

  • NioEventLoopGroup :Nio 事件循环组,循环监听注册的Channel的IO事件
  • ServerBootstrap :Netty服务端启动对象 ,需要把NioEventLoopGroup加入ServerBootstrap去启动
  • Bootstrap :ServerBootstrap是服务端的启动对象,Bootstrap是客户端的启动对象
  • ChannelInitializer :它提供了一种简单的方法来初始化Channel ,通过它把通道和handler绑定。
  • ChannelInboundHandlerAdapter :用于在消息管道中不同时机下处理消息,即有时间发生通过它来处理消息。也就是我们的handler

我们来写一个简单的服务端和客户端通信的案例,首先创建Maven项目,导入Maven依赖

<dependency>
  <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.42.Final</version>
</dependency>

服务端代码

对于服务端我们要做如下事情

  1. 创建两个NioEventLoopGroup ,一个作为BossGroup ,一个作为 WorkGroup
  2. 创建 ServerBootstrap 加入两个NioEventLoopGroup
  3. 通过 ServerBootstrap 添加Handler ,需要自己创建Handler
  4. 编写Handler ,通过继承ChannelInboundHandlerAdapter 来对不同的时间做不同的处理

服务端代码如下

public class NettyServer {
    public static void main(String[] args) throws InterruptedException {

        //创建Boss Group :负责处理链接
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();

        //创建 workGroup :负责处理读写事件
        NioEventLoopGroup workGroup = new NioEventLoopGroup();

        //创建服务端启动对象
        ServerBootstrap bootstrap = new ServerBootstrap();

        try{
            //把 bossGroup 和 workGroup 加入启动对象
            bootstrap
                    .group(bossGroup,workGroup)
                    //保存活动链接状态,启用该功能时,TCP会主动探测空闲连接的有效性
                    .childOption(ChannelOption.SO_KEEPALIVE,true)
                    //多个客户端过来,处理不过来的请求在队列排队,指定存放请求的队列的大小
                    .option(ChannelOption.SO_BACKLOG,64)
                    //指定服务器使用什么样的通道
                    .channel(NioserverSocketChannel.class)
                    //添加事件处理器Handler
                    .childHandler(new ChannelInitializer<SocketChannel>(){

                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //把处理器添加进去
                            ch.pipeline().addLast(new MyServerHandler());
                        }
                    });

            //到这里说明
            ChannelFuture future = bootstrap.bind(new InetSocketAddress("127.0.0.1", 6000)).sync();

            //对关闭通道进行监听
            //当此通道关闭时将收到通知
            future.channel().closeFuture().sync();

        }catch (Exception e){
            //关闭资源
            e.printStackTrace();
        }finally {
            workGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }

    }
}

handler代码如下

//这个Handler是用来处理客户端channel的IO事件
public class MyServerHandler extends ChannelInboundHandlerAdapter {

    //处理读事件 ChannelHandlerContext :上下文,含有通道,pipline ,地址 ;  msg就是数据
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buffer = (ByteBuf) msg;
        System.out.println("MyServerHandler,接收到:"+ctx.channel().remoteAddress()+"发来的消息:"+buffer.toString(CharsetUtil.UTF_8));
    }

    //数据读取完毕
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        //给客户端恢复消息
        ctx.writeAndFlush(Unpooled.copiedBuffer("你好,我收到了消息",CharsetUtil.UTF_8));
    }
}

客户端代码

客户端要做如下事情

  1. 创建 NioEventLoopGroup 用于监听服务端的事件
  2. 创建 Bootstrap启动对象 ,加入 NioEventLoopGroup
  3. 一样要通过 Bootstrap 添加Handler ,需要自己创建Handler
  4. 编写Handler ,通过继承ChannelInboundHandlerAdapter 来对不同的时间做不同的处理

客户端代码如下

public class NettyClient {
    public static void main(String[] args) throws InterruptedException {
        //客户端线程循环组
        NioEventLoopGroup eventExecutors = new NioEventLoopGroup();

        //客户端启动对象
        Bootstrap bootstrap = new Bootstrap();

        try {
            bootstrap.group(eventExecutors)
                    //指定客户端使用的通道类型
                    .channel(NioSocketChannel.class)
                    //添加客户端处理器
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //添加客户端处理器
                            ch.pipeline().addLast(new MyClientHandler());
                        }
                    });
            //链接服务端
            ChannelFuture channelFuture = bootstrap
                    .connect(new InetSocketAddress("127.0.0.1", 6000)).sync();
            //监听关闭事件
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            eventExecutors.shutdownGracefully();
        }
    }
}

客户端handler代码如下


//这个Handler是用来处理客户端channel的IO事件
public class MyClientHandler extends ChannelInboundHandlerAdapter {

    //链接激活
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //给服务端发送消息
        ctx.writeAndFlush(Unpooled.copiedBuffer("你好服务端",CharsetUtil.UTF_8));
    }

    //处理读事件 ChannelHandlerContext :上下文,含有通道,pipline ,地址 ;  msg就是数据
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buffer = (ByteBuf) msg;
        System.out.println("MyClientHandler,接收到:"+ctx.channel().remoteAddress()+"发来的消息:"+buffer.toString(CharsetUtil.UTF_8));
    }

    //处理异常
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

分别启动服务端和客户端,最终效果如下

  • 服务端
  • 客户端

文章到这就结束了,点赞还是要求一下的,万一屏幕面前的大帅哥,或者大漂亮一不小心就一键三连了啦,那我就是熬夜到头发掉光,也出下章

以上是关于八.Netty入门到超神系列-Netty入门程序的主要内容,如果未能解决你的问题,请参考以下文章

一.Netty入门到超神系列-BIONIOAIO的认识

九.Netty入门到超神系列-Netty开发Http服务器

七.Netty入门到超神系列-Netty介绍和线程模型

十一.Netty入门到超神系列-Netty使用Protobuf编码解码

十.Netty入门到超神系列-基于WebSocket开发聊天室

五.Netty入门到超神系列-零拷贝技术