netty简介及demo程序

目录

1.netty是什么

2.BIO和NIO的区别

3.netty的主要组件及概念

4.demo

1.server

2.serverHandler

3.client

4.clientHandler

5.启动


1.netty是什么

Netty是一款基于NIO(Nonblocking I/O,非阻塞IO)开发的网络通信框架,用于快速开发可维护的高性能协议服务器和客户端。简单来说它将java NIO进行了大量封装,大大降低了java NIO的上手难度。它具有并发高,传输快,封装好的优点。

2.BIO和NIO的区别

 

BIO:同步阻塞IO,在BIO中每一个连接都需要分配一个线程来执行,线程效率低。

NIO:异步非阻塞IO,引入了selector监听流事件,类似于收发室,不需要每个通信连接由一个单独的线程处理,解决了高并发的性能问题。

3.netty的主要组件及概念

  1. I/O:各种各样的流(文件、数组、缓冲、管道。。。)的处理(输入输出);
  2. Channel:通道,代表一个连接,每个Client请对会对应到具体的一个Channel;
  3. ChannelPipeline:责任链,每个Channel都有且仅有一个ChannelPipeline与之对应,里面是各种各样的Handler;
  4. handler:用于处理出入站消息及相应的事件,实现我们自己要的业务逻辑;
  5. EventLoopGroup:I/O线程池,负责处理Channel对应的I/O事件;
  6. ServerBootstrap:服务器端启动辅助对象;
  7. Bootstrap:客户端启动辅助对象;
  8. ChannelInitializer:Channel初始化器;
  9. ChannelFuture:代表I/O操作的执行结果,通过事件机制,获取执行结果,通过添加监听器,执行我们想要的操作;
  10. ByteBuf:字节序列,通过ByteBuf操作基础的字节数组和缓冲区。

4.demo

新建一个springboot项目,然后引入netty依赖包

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

1.server

/**
 * (1)、 初始化用于Acceptor的主"线程池"以及用于I/O工作的从"线程池";
 * (2)、 初始化ServerBootstrap实例, 此实例是netty服务端应用开发的入口;
 * (3)、 通过ServerBootstrap的group方法,设置(1)中初始化的主从"线程池";
 * (4)、 指定通道channel的类型,由于是服务端,故而是NioServerSocketChannel;
 * (5)、 设置ServerSocketChannel的处理器
 * (6)、 设置子通道也就是SocketChannel的处理器, 其内部是实际业务开发的"主战场"
 * (8)、 配置子通道也就是SocketChannel的选项
 * (9)、 绑定并侦听某个端口
 */
public class NettyServer {
    private final int port;

    public NettyServer(int port) {
        this.port = port;
    }

    public void start() throws InterruptedException {

        // 服务器端应用程序使用两个NioEventLoopGroup创建两个EventLoop的组,EventLoop这个相当于一个处理线程,是Netty接收请求和处理IO请求的线程。
        // 主线程组, 用于接受客户端的连接,但是不做任何处理,跟老板一样,不做事
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);

        // 从线程组, 当boss接受连接并注册被接受的连接到worker时,处理被接受连接的流量。
        EventLoopGroup workerGroup = new NioEventLoopGroup(1);
        try {
            // netty服务器启动类的创建, 辅助工具类,用于服务器通道的一系列配置
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            /**
             * 使用了多少线程以及如何将它们映射到创建的通道取决于EventLoopGroup实现,甚至可以通过构造函数进行配置。
             * 设置循环线程组,前者用于处理客户端连接事件,后者用于处理网络IO(server使用两个参数这个)
             * public ServerBootstrap group(EventLoopGroup group)
             * public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup)
             */
            //传入线程组
            serverBootstrap.group(bossGroup, workerGroup);

            //指定NIO的模式
            serverBootstrap.channel(NioServerSocketChannel.class);

            /**
             * @Description: 服务端每接收到一个连接请求就会新启一个socket通信,也就是channal,下面代码就是给channal添加handler
             *
             @Override protected void initChannel(SocketChannel channel) throws Exception {
             // 通过SocketChannel去获得对应的管道
             ChannelPipeline pipeline = channel.pipeline();

             // 通过管道,添加handler
             pipeline.addLast("nettyServerOutBoundHandler", new NettyServerOutBoundHandler());
             pipeline.addLast("nettyServerHandler", new NettyServerHandler());
             }
             */
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    //添加handler
                    socketChannel.pipeline().addLast(new NettyServerHandler());
                }
            });
            //启动server,绑定端口,开始接收进来的连接,设置启动的端口号,同时启动方式为同步
            ChannelFuture future = serverBootstrap.bind(port).sync();

            //监听关闭的channel,等待服务器 socket 关闭 ,设置位同步方式
            future.channel().closeFuture().sync();
        } finally {
            //关闭线程组
            bossGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
        }

    }

    public static void main(String args[]) throws InterruptedException {
        int port = 8088;
        NettyServer nettyServer = new NettyServer(port);
        System.out.println("server start");
        nettyServer.start();
        System.out.println("server stop");
    }
}  

2.serverHandler

public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * @param [ctx, msg]
     * @return void
     * @author pwd
     * @description 读取客户端发送的消息
     * @date 2022/7/13 15:43
     **/
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("read client msg");
        ByteBuf result = (ByteBuf) msg;
        byte[] bytesMsg = new byte[result.readableBytes()];
        // msg中存储的是ByteBuf类型的数据,把数据读取到byte[]中
        result.readBytes(bytesMsg);
        String resultStr = new String(bytesMsg);
        // 接收并打印客户端的信息
        System.out.println("Client said:" + resultStr);

        //如果客户端骂人则反弹伤害
        if(resultStr.contains("SB")){
            // 在当前场景下,发送的数据必须转换成ByteBuf数组
            ByteBuf encoded = ctx.alloc().buffer(4 * resultStr.length());
            encoded.writeBytes(resultStr.getBytes());
            ctx.writeAndFlush(encoded);
        }
        // 释放资源,这行很关键
        result.release();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 当出现异常就关闭连接
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    /**
     * @author pwd
     * @description 给客户端发送消息
     * @date 2022/7/13 15:47
     * @param [ctx]
     * @return void
     **/
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        // 向客户端发送消息
        String response = "hello client!";
        // 在当前场景下,发送的数据必须转换成ByteBuf数组
        ByteBuf encoded = ctx.alloc().buffer(4 * response.length());
        encoded.writeBytes(response.getBytes());
        ctx.writeAndFlush(encoded);
    }
}

3.client

ublic class NettyClient {
    private final int port;
    private final String host;

    public NettyClient(String host,int port){
        this.host = host;
        this.port = port;
    }
    public void start() throws InterruptedException {

        //线程组
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        // 客户端启动类程序
        Bootstrap bootstrap = new Bootstrap();
        try{
            bootstrap.group(workerGroup);
            //指定NIO的模式
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.option(ChannelOption.SO_KEEPALIVE, true);

            //设置客户端handler
            bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    socketChannel.pipeline().addLast(new NettyClientHandler());
                }
            });
            /** 开启客户端监听,连接到远程节点,阻塞等待直到连接完成*/
            ChannelFuture channelFuture = bootstrap.connect(host,port).sync();
            /**阻塞等待数据,直到channel关闭(客户端关闭)*/
            channelFuture.channel().closeFuture().sync();
        }finally {
            workerGroup.shutdownGracefully().sync();
        }

    }

    public static void main(String args[]) throws InterruptedException {
        String host="127.0.0.1";
        int port =8088;
        NettyClient nettyClient = new NettyClient(host,port);
        System.out.println("client start");
        nettyClient.start();
        System.out.println("client stop");
    }
}

4.clientHandler

public class NettyClientHandler extends SimpleChannelInboundHandler<ByteBuf> {

    /**
     * @author pwd
     * @description 读取server发送过来的消息
     * @date 2022/7/13 15:53
     * @param [channelHandlerContext, byteBuf]
     * @return void
     **/
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
        System.out.println("server said:"+byteBuf.toString(CharsetUtil.UTF_8));

        //客户端很低俗,每次都说脏话,不要学
        String msg = "you are SB";
        ByteBuf encoded = channelHandlerContext.alloc().buffer(4 * msg.length());
        encoded.writeBytes(msg.getBytes());
        channelHandlerContext.writeAndFlush(encoded);
        Thread.sleep(1000);
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        //异常退出
        cause.printStackTrace();
        ctx.close();
    }

    /**
     * @author pwd
     * @description 给server发送消息
     * @date 2022/7/13 15:54
     * @param [ctx]
     * @return void
     **/
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        String msg = "hello Server!";
        ByteBuf encoded = ctx.alloc().buffer(4 * msg.length());
        encoded.writeBytes(msg.getBytes());
        ctx.writeAndFlush(encoded);

    }
}

5.启动

1.执行server的main方法

2.执行client的main方法

可以在server控制台看到

read client msg
Client said:hello Server!
read client msg
Client said:you are SB
read client msg
Client said:you are SB

可以在client控制台看到

server said:hello client!
server said:you are SB
server said:you are SB
server said:you are SB
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值