java IO、netty学习

本文详细介绍了BIO、NIO和Netty三种不同的网络I/O模型。BIO是阻塞I/O,无法同时处理多个连接,而NIO引入了非阻塞I/O和多路复用,优化了并发性能。Netty作为基于NIO的网络通信框架,进一步简化了NIO的使用,提供了更好的并发性能和易用性,如Reactor模型和零拷贝技术。通过对Netty的使用,开发者可以更专注于业务处理,而不是底层I/O操作。
摘要由CSDN通过智能技术生成

一、BIO

阻塞io,存在无法同时支持多个连接问题,新建线程处理数据优化该问题,引发的问题是线程数可能过多,内存资源不足;引入线程池会限制并发数,由线程池决定连接数,阻塞等待数据也会占用线程池线程资源。

public class SocketServer {
    public static void main(String[] args) throws  IOException{
    //初始化ServerSocket ,绑定端口
            ServerSocket sc = new ServerSocket(9000);
            while(true){
                System.out.println("等待连接。。。。");
                //阻塞等待连接,accept接收客户端连接
                Socket clientSocket  = sc.accept();
                //新开线程处理数据
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            handler(clientSocket);
                        }catch (IOException e){

                        }
                    }
                });
                System.out.println("存在连接。。。");
                //不新开线程处理
               // handler(clientSocket);
            }
    }

    private static void handler( Socket clientSocket ) throws IOException{
              byte[] bytes = new byte[1024];
              System.out.println("read....");
              //阻塞接收数据,没有数据则阻塞
              int read = clientSocket.getInputStream().read(bytes);
              if(read!=-1){
                  System.out.println("data:"+new String(bytes,0,read));
              }
    }
}

二、NIO

非阻塞io,相比BIO可以支持多个连接,优化数据读取。
多路复用底层原理
epoll_create:创建epoll实例,使用文件描述符表示
epoll_ctl:将连接等绑定到epoll上,监听事件
epoll_wait:阻塞等待事件发生,通过操作系统中断机制感知事件
在这里插入图片描述

public class NioServer {
    static List<SocketChannel> channelList = new ArrayList<>();
    public static void main(String[] args) throws IOException {
        //创建nio的serverSocketChannel,与Bio的ServerSocket类似
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(9000));
        //连接配置为非阻塞
        serverSocketChannel.configureBlocking(false);
        Selector selector = Selector.open();//epoll实例对象文件描述符表示,后续存放注册事件
        //Channel注册搭配多路复用器,selector注册连接事件,优化无效遍历连接消耗了性能的问题
        SelectionKey selection = serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
        while(true){
            //阻塞等待需要处理的事件
            selector.select();
            //获取注册的全部事件实例
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while(iterator.hasNext()){
                SelectionKey key = iterator.next();
                if(key.isAcceptable()){
                    //是连接事件,进行连接获取,事件注册
                    ServerSocketChannel server =(ServerSocketChannel)key.channel();
                    SocketChannel socketChannel = server.accept();
                    socketChannel.configureBlocking(false);
                    //可以注册读写事件
                    SelectionKey selKey = socketChannel.register(selector,SelectionKey.OP_READ);

                }else if(key.isReadable()){
                    SocketChannel socketChannel = (SocketChannel)key.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(128);
                //非阻塞
                int len = socketChannel.read(byteBuffer);
                if(len>0){
                    System.out.println("data:"+new String(byteBuffer.array()));
                }else
                    //客户端断开连接关闭socket
                    if(len == -1){
                       socketChannel.close();
                    }
                }
                //事件集合去除key,避免重复处理
                iterator.remove();
            }
        }
        //简易NIO,一个线程可处理多个连接
//创建nio的serverSocketChannel,与Bio的ServerSocket类似
//  ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//  serverSocketChannel.socket().bind(new InetSocketAddress(9000));
     //连接配置为非阻塞
//   serverSocketChannel.configureBlocking(false);
//        while(true){
//            //非阻塞,底层调用Linux的accept方法
//            SocketChannel socketChannel = serverSocketChannel.accept();
//            if(socketChannel!=null){//如果有客户端连接
//                //读取数据设置非阻塞
//                socketChannel.configureBlocking(false);
//                //保存连接
//                channelList.add(socketChannel);
//            }
            //遍历连接读取数据,存在问题大量连接无数据也需遍历,消耗性能
//            Iterator<SocketChannel> iterator = channelList.iterator();
//            while(iterator.hasNext()){
//                SocketChannel sc = iterator.next();
//                ByteBuffer byteBuffer = ByteBuffer.allocate(128);
//                //非阻塞
//                int len = sc.read(byteBuffer);
//                if(len>0){
//                    System.out.println("data:"+new String(byteBuffer.array()));
//                }else
//                    //客户端断开连接,去掉
//                    if(len == -1){
//                        iterator.remove();
//                    }
//            }
//        }
    }
}

在这里插入图片描述

三、Netty

netty是一款基于NIO(Nonblocking I/O,非阻塞IO)开发的网络通信框架,对比于BIO(Blocking I/O,阻塞IO),他的并发性能得到了很大提高。
Netty对NIO做了封装优化,不关心如何建立连接注册事件,只关心如何处理收发数据,更加简便开发NIO程序,使用也很简单,以下就是简单示例,主要就是实现HandlerAdapter,覆写方法。

public class NettyServer {
    public static void main(String[] args) throws Exception {
        EventLoopGroup boosGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup(8);
        try{
            //服务端启动对象
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(boosGroup,workerGroup)//绑定两个线程池
                    .channel(NioServerSocketChannel.class)//服务器通道
                    //服务器队列大小,排队
                    .option(ChannelOption.SO_BACKLOG,1024)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                        protected  void initChannel(SocketChannel ch) throws  Exception{
                        //设置处理器
                        ch.pipeline().addLast(new NettyServerHandler());
                    }
                    });
            //启动服务器绑定端口
            ChannelFuture cf = bootstrap.bind(9000).sync();
            cf.channel().closeFuture().sync();
        }catch (Exception e){
                 boosGroup.shutdownGracefully();
                 workerGroup.shutdownGracefully();
        }
    }
}

/**
 * 自定义处理器,需要继承netty规定的HandlerAdapter
 */
public class NettyServerHandler  extends ChannelInboundHandlerAdapter {
    /**
     * 客户端连接服务器完成触发
     * @param ctx
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx){
        System.out.println("连接建立。。。");
    }
    /**
     * 读取客户端数据
     * @param ctx 上下文对象,通道channnel 管道 pipeline
     * @param msg 数据
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx,Object msg){
        Channel channel = ctx.channel();
        ChannelPipeline pipeline = ctx.pipeline();//双向链接
        ByteBuf buf = (ByteBuf)msg;
        System.out.println("data。。。"+buf.toString(CharsetUtil.UTF_8));
    }
    /**
     * 数据读取完毕处理方法
     * @param ctx
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx){
        ByteBuf buf = Unpooled.copiedBuffer("aa".getBytes(CharsetUtil.UTF_8));
       //发送数据
        ctx.writeAndFlush(buf);
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause){
       ctx.close();
    }

}

相比于NIO,netty优化大量连接建立进行读写,后续新建连接等待超时的问题,利用主selector进行连接建立,多selector处理数据。worker group最终回调pipeline中的hander里处理数据方法。
原理:Reactor响应式模型
在这里插入图片描述

零拷贝:使用直接内存(本机物理内存),利用的是直接内存的引用。
在这里插入图片描述
[1] https://www.jianshu.com/p/b9f3f6a16911
[2] https://www.bilibili.com/video/BV1Ui4y1T7yf
[3] https://www.bilibili.com/video/BV1Vy4y1J7DG

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值