5. 彤哥说netty系列之Java NIO核心组件之Channel

nio

你好,我是彤哥,本篇是netty系列的第五篇。html

简介

上一章咱们一块儿学习了如何使用Java原生NIO实现群聊系统,这章咱们一块儿来看看Java NIO的核心组件之一——Channel。java

思惟转变

首先,我想说的最重要的一个点是,学习NIO思惟必定要从BIO那种一个链接一个线程的模式转变成多个链接(Channel)共用一个线程来处理的这种思惟。linux

nio

nio

1个Connection = 1个Socket = 1个Channel,这几个概念能够看做是等价的,都表示一个链接,只不过是用在不一样的场景中。

若是单从阻塞/非阻塞的角度来看的话,IO能够分红两大类,一类是Blocking IO,一类是Non-blocking IO,像IO五种模型中的后四种其实均可以看做是非阻塞型IO,只是各自使用的手段不相同罢了。编程

在Java中,咱们说的非阻塞IO或者说NIO(New IO)主要是指多路复用IO,底层可使用select/poll/epoll等技术实现。segmentfault

另外,在Java1.7的时候引入了NIO2,这个主要是指异步IO模型,也就是咱们常说的AIO,底层彻底使用异步回调的方式来实现。数组

可是,因为AIO这项技术在linux操做系统上还不太成熟,因此咱们一般也不会说太多关于这方面的内容。网络

在后面咱们学习Netty的时候会再次讲到这三种IO模型,能够看到Netty是彻底支持三种IO的,可是它把OIO(BIO)和AIO都给deprecated了,也进一步说明了AIO的不成熟性。架构

好了,扯了一下思惟转变的问题,下面正式进入今天的内容——Java NIO核心组件之Channeldom

Channel

概念

咱们先来看看Java中对于Channel的定义,位于java.nio.channels.Channel类的注释上:异步

A nexus for I/O operations.
本文来源工从号彤哥读源码
A channel represents an open connection to an entity such as a hardware device, a file, a network socket, or a program component that is capable of performing one or more distinct I/O operations, for example reading or writing.

第一句,它是IO操做的一种链接。

nexus, the means of connection between things linked in series.

第二句,Channel表明到实体的开放链接,这个实体能够是硬件,文件,网络套接字,或者程序组件,而且能够执行一个或多个不一样的IO操做,例如,读或写。

简单点讲,Channel就是实体与实体之间的链接,好比,操做文件可使用FileChannel,操做网络可使用SocketChannel等。

与流的区别

BIO是面向流(Stream)编程的,流又分红InputStream和OutputStream,那么Channel和Stream有什么区别呢?

  • Channel能够同时支持读和写,而Stream只能支持单向的读或写(因此分红InputStream和OutputStream)
  • Channel支持异步读写,Stream一般只支持同步
  • Channel老是读向(read into)Buffer,或者写自(write from)Buffer(有点绕,以Channel为中心,从Channel中读出数据到Buffer,从Buffer中往Channel写入数据)

nio

实现方式

下面列举了JDK中比较重要的实现方式:

  • FileChannel:操做文件
  • DatagramChannel:UDP协议支持
  • SocketChannel:TCP协议支持
  • ServerSocketChannel:监听TCP协议Accept事件,以后建立SocketChannel

例子

public class FileChannelTest {
    public static void main(String[] args) throws IOException {
        // 从文件获取一个FileChannel
        FileChannel fileChannel = new RandomAccessFile("D:\\object.txt", "rw").getChannel();
        // 声明一个Byte类型的Buffer
        ByteBuffer buffer = ByteBuffer.allocate(10);
        // 将FileChannel中的数据读出到buffer中,-1表示读取完毕
        // buffer默认为写模式,本文来源工从号彤哥读源码
        // read()方法是相对channel而言的,相对buffer就是写
        while ((fileChannel.read(buffer)) != -1) {
            // buffer切换为读模式
            buffer.flip();
            // buffer中是否有未读数据
            while (buffer.hasRemaining()) {
                // 未读数据的长度
                int remain = buffer.remaining();
                // 声明一个字节数组
                byte[] bytes = new byte[remain];
                // 将buffer中数据读出到字节数组中
                buffer.get(bytes);
                // 打印出来
                System.out.println(new String(bytes, StandardCharsets.UTF_8));
            }
            // 清空buffer,为下一次写入数据作准备
            // clear()会将buffer再次切换为写模式
            buffer.clear();
        }
    }
}

能够看到,Channel与Buffer是息息相关的。注意这里的读写方法,调用者是谁就以谁为核心,channel.read()就表示从channel读出数据,buffer.get()就表示从buffer读出数据,这跟传统编程的角度不太同样的地方。

总结

今天咱们学习了Java NIO核心组件之Channel,它与传统BIO中的流很相似但又有所区别,且常常与Buffer联合起来使用,Buffer又是什么呢?请听下回分解。

参考

挺不错的一个网站:

http://tutorials.jenkov.com/j...

最后,也欢迎来个人工从号彤哥读源码系统地学习源码&架构的知识。

nio

相关文章
相关标签/搜索