了解一下NIO

来源:互联网 发布:拳皇98出招优化 编辑:程序博客网 时间:2024/04/29 09:31

NIO(Non-block I/O)初学

  • 解释:非阻塞I/O
  • 类库

    • 缓冲区(buffer)
      • I/O操作,将数据写入缓冲区,方便特有操作,也方便网络读写。
    • 通道(channel)
      • 通道是双向的,可以同时进行读写,网络数据通过Channel读取和写入;stream(流)是单向的,只能读或者写
      • 通道分为两大类:用于网络读写的SelectableChannel和文件操作的FileChannel
      • ServerSocketChannel和SocketChannel都是SelectableChannel子类
    • 多路复用器(Selector):轮询出发生读或写操作的Channel
      • JDK使用epoll(),只需要一个线程负责Selector轮询。

    Java原生NIO编程

    • NIO服务端序列图

      • 打开ServerSocketChannel,用于监听客户端的连接,它是所有客户端连接的父管道。ServerSocketChannel acceptorSvr = ServerSocketChannel.open();
      • 绑定监听端口,设置连接方式为非阻塞模式
        ( acceptorSvr .socket().bind(new InetSocketAddress(InetAddress.getByName(“IP”),port));
        acceptorSvr .configureBlocking(false))
      • 创建Reactor线程,创建多路复用器并启动线程(
        Selector selector =Selector.open();
        New Thread(new ReactorTask()).start();
      • 将ServerSocketChannel注册到Reactor线程的多路复用器Selector上,监听ACCEPT事件
        SelectionKey key = acceptorSvr.register(selector,SelectionKey.OP_ACCEPT,ioHandler);
      • 多路复用器在线程run方法的无限循环轮询准备就绪的Key
        int num = selector.select();
        Set selectedKeys = selector.selectedKeys();
        Iterator it = selectedKeys.iterator();
        while(it.hasNext()){
        SelectionKey key = (SelectionKey)it.next();
        //… deal with I/O event
        }
      • 多路复用器监听到有新的客户端接入,处理新的接入请求,完成tcp三次握手,建立物理链路。
        SocketChannel channel =svrChannel.accept();
      • 设置客户端链路为非阻塞模式
        channel.configureBlocking(false);
        channel.socket().setReuseAddress(true);
      • 将新接入的客户端连接注册到Reactor线程的多路复用器上,监听读操作,读取客户端发送的网络信息
        SelectionKey key = socketChannel.register(selector,SelectionKey.OP_READ,ioHandler);
      • 异步读取客户端请求消息到缓冲区
        int readNumber = channel.read(receivedBuffer);
      • 对ByteBuffer进行编解码,如果有半包消息指针reset,继续读取后续的报文,将解码成功的消息封装成Task,投递到业务线程池中,进行业务逻辑编排。
        Object message =null;
        while(buffer.hasRemain()){
        byteVuffer.mark();
        Object message = decode(byteBuffer)’
        if(message == null){
        byteBuffer.reset();
        break;
        }
        messageList.add(message);
        }
        if(!byteBuffer.hasRemain()){
        byteBuffer.clear()
        }else{
        byteBuffer.compact();
        }
        if(messageList!=null& !messageList.isEmpty()){
        for(Object messageE :messageList){
        handlerTask(messageE);
        }
        }

      • 将pojo对象encode(编码)成ByteBuffer,调用SocketChannel的异步write接口,将消息异步发送给客户端。
        socketChannel.write(buffer);

Netty NIO

  1. 运行环境
    IDE(Eclipse、intelIED…)、Netty.jar
  2. 服务器端
    a.开发步骤
    1、配置服务端的NIO线程组
    2、绑定端口,同步等待成功
    3、等待服务端监听端口关闭
    4、退出,释放线程组资源
  3. 客户端
    1、配置客户端的NIO线程组
    2、 创建客户端辅助启动类Bootstrap,进行配置
    3、设置ChannelHander到管道(ChannelPipleline)中,用于处理IO事件
    4、辅助类设置完成调用connect发起异步连接,然后调用同步方法等待连接成功。
    5、客户端连接关闭,客户端主函数退出,释放资源

打包部署

1、eclipse导出jar包
2、ant打包工具
3、Maven工程构建

TCP粘包/拆包问题的解决之道

TCP粘包/拆包解决策略

1、消息定长2、在包尾增加回车换行符进行分割3、将消息分为消息头和消息体4、更复杂的应用层协议

LineBasedFrameDecoder和StringDecoder原理

LingBasedFrameDecoder的工作原理:

依次遍历ByteBuf中可读的字节,判断是否存在“\n”或者"\r\n"作为结束位置的标志。    1、以换行符作为结束标志的解码器    2、支持携带结束符或者不携带结束符两种解码方式    3、支持配置单行的最大长度

Stringdecoder功能简单:

1、将接收到的对象转换成字符串2、调用后面的handler

LingBasedFrameDecoder和StringDecoder组合就是按行切换的文本解码器,用来支持TCP的粘包和拆包。

分隔符和定长解码器的应用

 另外两种解码器(都能解决TCP粘包和拆包导致的读半包问题):     1、DelimiterBasedFrameDecoder:自动完成以分隔符作为结束标志的消息解码     2、FixedLengthFrameDecoder:自动完成对定长消息的解码

DelimiterBasedFrameDecoder 应用

1 0
原创粉丝点击