zoukankan      html  css  js  c++  java
  • NIO-Channel



    NIO-Channel

    目录

    NIO-概览
    NIO-Buffer
    NIO-Channel
    NIO-Channel接口分析
    NIO-SocketChannel源码分析
    NIO-FileChannel源码分析
    NIO-Selector源码分析
    NIO-WindowsSelectorImpl源码分析
    NIO-EPollSelectorIpml源码分析

    前言

    本来是想学习Netty的,但是Netty是一个NIO框架,因此在学习netty之前,还是先梳理一下NIO的知识。通过剖析源码理解NIO的设计原理。

    本系列文章针对的是JDK1.8.0.161的源码。

    什么是Channel

    通道(Channel)是对原I/O包中的流的模拟。与文件设备I/O交互的所有数据都必须通过一个Channel对象。

    上一节我们提到在NIO中使用缓冲区来存放指定基元的数据,我们可以通过Buffer来读写数据。
    将数据写入到硬盘时,我们可以将字节数据写入到缓冲区中;若我们要从硬盘读取数据,则需要通过通道将数据写入到缓冲区,然后再从缓冲区读取数据。

    通道类型

    根据不同的使用方式,分为不同的通道。比如我们需要网络读写,就需要网络交互的通道。需要文件读写就需要文件交互的通道。
    NIO实现了Sctp协议、TCP协议、UDP协议以及文件传输四种通道,同时还实现了Windows平台的异步Socket通道以及异步文件通道。

    windows平台的异步I/O是通过重叠I/O和IOCP(I/O完成端口)实现的,想要了解windows异步I/O的知识可以看一下我另一篇文章《Windows内核原理-同步IO与异步IO》

    类型 通道
    Sctp协议客户端 SctpChannel
    Sctp协议多播客户端 SctpMultiChannel
    Sctp协议服务端 SctpServerChannel
    UDP协议 DatagramChannel
    TCP协议同步I/O服务端 ServerSocketChannel
    TCP协议同步I/O客户端 ServerChannel
    文件读写 FileChannel

    对于Windows平台的异步通道

    类型 通道
    TCP协议异步I/O服务端 WindowsAsynchronousServerSocketChannel
    TCP协议异步I/O客户端 WindowsAsynchronousSocketChannel
    异步文件读写 WindowsAsynchronousFileChannel

    另外NIO还实现了一个单向通讯管道(Pipe)的功能,通过引入SourceChannelSinkChannel实现,底层实际还是Socket通讯。

    如何使用

    在介绍不同的Channel的实现之前我们先介绍下Channel如何使用。

    ServerSocketChannel

    以TCP协议为例,我们进行网络收发的时候,首先需要创建一个ServerSocketChannel用于监听端口。

    //创建一个服务端socket通道用于接收连接
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    //绑定监听地址
    serverSocketChannel.socket().bind(new InetSocketAddress(8080));
    //等待连接
    SocketChannel socketChannel = serverSocketChannel.accept();
    

    我们监听了8080端口。若没有连接时,线程会阻塞在accept

    当有收到新的连接创建时,会获取到SocketChannel,此时我们需要创建一个Buffer用来从Channel中读取数据。

    ByteBuffer buf = ByteBuffer.allocate(1024);
    //数据将写入到buffer中
    int length = socketChannel.read(buf);
    

    数据写入到我们的Buffer中,我们就需要将他们读出来

    buf.flip();  //转化为可读模式
    byte[] data = new byte[length];
    buf.get(data);
    

    将数据从Buffer写入到Channel时

    buf.clear(); 
    byte[] resp = {'O','K'};
    buf.put(resp);
    buf.flip();//转换为读模式
    socketChannel.write(buf);
    

    这里为了方便直接使用原来的Buffer。

    SocketChannel

    作为客户端我们需要创建一个SocketChannel。

    SocketChannel.open();
    client.connect(new InetSocketAddress("127.0.0.1", 6060));
    

    发送HELLO给服务端

    ByteBuffer buffer = ByteBuffer.allocate(10);
    byte[] data = {'H', 'E', 'L', 'L', 'O'};
    buffer.put(data);
    buffer.flip();//转换为读模式
    client.write(buffer);
    

    阻塞等待读取数据

    buffer.clear();
    client.read(buffer);
    buffer.flip();//转换为读模式
    

    处理完成,需要关闭释放连接

    //关闭客户端输入流
    client.socket().shutdownInput();
    //关闭客户端输出流
    client.socket().shutdownOutput();
    //关闭客户端socket时会关闭客户端channel
    client.socket().close();
    //关闭客户端channel,会同时关闭输入和输出流。
    client.close();
    

    关闭输出流会发送FIN包,若输入流未关闭仍然可以继续接收数据,这就是TCP的半连接。若处理完最后需要确保channel关闭。

    FileChannel

    FileChannel只能被FileInputStream、FileOutputStream、RandomAccessFile创建

    RandomAccessFile

    使用RandomAccessFile创建FileChannel

    //第一个参数时文件名,第二个参数是读写方式
    RandomAccessFile randomAccessFile = new RandomAccessFile("1.txt","rw");
    FileChannel channel = randomAccessFile.getChannel();
    

    FileInputStream

    使用RandomAccessFile创建FileChannel

    FileInputStream  inputStream = new FileInputStream("1.txt");
    channel  = inputStream.getChannel();
    

    inputStream获取的FileChannel只能读

    FileOutputStream

    使用RandomAccessFile创建FileChannel

    
    FileOutputStream outputStream = new FileOutputStream("1.txt");
    channel  = outputStream.getChannel();
    

    inputStream获取的FileChannel只能写

    关闭FileChannel

    关闭FileChannel的方法和关闭SocketChannel方法一样。

    //关闭channel时会关闭文件
    channel.close();
    //关闭文件时会关闭channel
    randomAccessFile.close();
    //关闭文件流时会关闭channel
    inputStream.close();
    //关闭文件流时会关闭channel
    inputStream.close();
    

    总结

    由于源码解析的篇幅较长,因此将channel源码单独分出来讲解。

    相关文献

    1. SCTP协议详解
    2. 史上最强Java NIO入门:担心从入门到放弃的,请读这篇!
    3. Java NIO系列教程

    20191127212134.png
    微信扫一扫二维码关注订阅号杰哥技术分享
    出处:https://www.cnblogs.com/Jack-Blog/p/12015516.html
    作者:杰哥很忙
    本文使用「CC BY 4.0」创作共享协议。欢迎转载,请在明显位置给出出处及链接。

  • 相关阅读:
    MySQL 对于千万级的大表要怎么优化?
    随便写的一些docker使用操作命令
    零基础学python大概要多久?我用了30天
    普通人学python有意义吗?意义重大
    华为私有云组件
    Mysql 调优(二)分析思路
    MySQL 调优(一)调优原则
    shell脚本获取当前时间,分钟之前时间、小时之前时间和天之前时间
    java_windows环境变量自动设置脚本
    plsql中文乱码问题解决方案
  • 原文地址:https://www.cnblogs.com/Jack-Blog/p/12015516.html
Copyright © 2011-2022 走看看