NIO-Channel接口分析

简介: NIO-Channel接口分析

前言

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

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

上一篇介绍了Channel的基本使用,下面对Channel的接口进行分析。

接口

SCTP协议

SCTP(Stream Control Transmission Protocol)是一种传输协议,在TCP/IP协议栈中所处的位置和TCP、UDP类似,兼有TCP/UDP两者特征。

对于SCTP协议这里不详细描述,想了解的同学可以看下这篇文章

SCTP协议平时用的不多,这里不做具体讨论。

UDP协议

NIO使用DatagrmChannel实现了UDP协议的网络通讯。

下面我们对各个接口进行分析。

AutoCloseableCloseable分别是自动关闭和主动关闭接口。当资源(如句柄或文件等)需要释放时,则需要调用close方法释放资源。

public interface AutoCloseable {
    void close() throws Exception;
}
 
public interface Closeable extends AutoCloseable {
    void close() throws IOException;
}

Channel是通道接口,针对于I/O相关的操作,需要打开和关闭操作。

public interface Channel extends Closeable {
    boolean isOpen();
 
    void close() throws IOException;
}

InterruptibleChannel是支持异步关闭和中断的通道接口。为了支持Thead的interrupt模型,当线程中断时,可以执行中断处理对象的回调,从而关闭释放Channel。

public interface InterruptibleChannel extends Channel {
    void close() throws IOException;
}

关于InterruptibleChannel可中断I/O详细解析可以看一下《JDK源码阅读-InterruptibleChannel与可中断IO》

Interruptible是线程中断接口,即上面提的Thead的interrupt模型。当线程中断时,则会调用中断操作。

public abstract interface Interruptible {
    public abstract void interrupt(java.lang.Thread t);
}
public class Thread implements Runnable {
    ...
    public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();
 
        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }
    ...
}

AbstractInterruptibleChannel实现了ChannelInterruptibleChannel接口。

  • closeLock是关闭时的锁
  • open表示channle是否打开
  • interuptorInterruptible中断回调
  • interrupted为I/O执行时的线程
public abstract class AbstractInterruptibleChannel implements Channel, InterruptibleChannel {
    ...
    public final void close() throws IOException {
        synchronized(this.closeLock) {
            if (this.open) {
                this.open = false;
                this.implCloseChannel();
            }
        }
    }
    //具体的Channel实现关闭
    protected abstract void implCloseChannel() throws IOException;
 
    protected final void begin() {
        if (this.interruptor == null) {
            this.interruptor = new Interruptible() {
                //线程中断时,则会调用该接口关闭Channel
                public void interrupt(Thread target) {
                    synchronized(AbstractInterruptibleChannel.this.closeLock) {
                        if (AbstractInterruptibleChannel.this.open) {
                            AbstractInterruptibleChannel.this.open = false;
                            AbstractInterruptibleChannel.this.interrupted = target;
 
                            try {
                                AbstractInterruptibleChannel.this.implCloseChannel();
                            } catch (IOException x) {
                            }
 
                        }
                    }
                }
            };
        }
        //将线程的blockOn设置为当前interruptor,从而使得线程关闭时能关闭channel
        blockedOn(this.interruptor);
        Thread me = Thread.currentThread();
        if (me.isInterrupted()) {
            this.interruptor.interrupt(me);
        }
 
    }
 
    protected final void end(boolean completed)
        throws AsynchronousCloseException
    {
        //I/O结束,清除线程blocker
        blockedOn(null);
        Thread interrupted = this.interrupted;
        if (interrupted != null && interrupted == Thread.currentThread()) {
            interrupted = null;
            throw new ClosedByInterruptException();
        }
        if (!completed && !open)
            throw new AsynchronousCloseException();
    }
 
    static void blockedOn(Interruptible intr) {
        SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), intr);
    }
}

AbstractInterruptibleChannel添加了beginend方法。 在I/O操作开始时会调用begin,在I/O操作结束时会调用end。在begin方法内将中断操作加入到当前线程中。最终会调用到线程的blockOn方法,它会将该中断接口注入到线程中,使得线程中断时可以调用到Channel并释放相关资源。

public void blockedOn(Thread t, Interruptible b) {
    t.blockedOn(b);
}

SelectableChannel接口声明了Channel是可以被选择的,在Windows平台通过WindowsSelectorImpl实现,Linux通过EPollSelectorImpl实现。此外还有KQueue等实现,关于Selector具体细节在《NIO-Selector》一文中会介绍。

AbstractSelectableChannel实现了SelectableChannel接口。

NetworkChannel适用于网络传输的接口。

public interface NetworkChannel extends Channel {
    //绑定地址
    NetworkChannel bind(SocketAddress var1) throws IOException;
 
    //获取本地地址
    SocketAddress getLocalAddress() throws IOException;
 
    //设置socket选项
    <T> NetworkChannel setOption(SocketOption<T> var1, T var2) throws IOException;
    //获取socket选项
    <T> T getOption(SocketOption<T> var1) throws IOException;
    //当前通道支持的socket选项
    Set<SocketOption<?>> supportedOptions();
}

MulticastChannel是支持组播接口。

public interface MulticastChannel extends NetworkChannel {
    void close() throws IOException;
 
    MembershipKey join(InetAddress group, NetworkInterface interf) throws IOException;
 
    MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source) throws IOException;
}

SelChImpl接口用于将底层的I/O就绪状态更新为就绪事件。

public interface SelChImpl extends Channel {
 
    FileDescriptor getFD();
    int getFDVal();
    //更新就绪事件
    public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk);
    //设置就绪事件
    public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk);
    //将底层的轮询操作转换为事件
    void translateAndSetInterestOps(int ops, SelectionKeyImpl sk);
    //返回channle支持的操作,比如读操作、写操作等
    int validOps();
    void kill() throws IOException;
}

由于UDP支持读写数据,因此还实现了ReadableByteChannelWritableByteChannel接口

public interface ReadableByteChannel extends Channel {
    int read(ByteBuffer dst) throws IOException;
}   
 
public interface WritableByteChannel extends Channel {
    int write(ByteBuffer src) throws IOException;
}

ByteChannel是支持读写的通道。

public interface ByteChannel extends ReadableByteChannel, WritableByteChannel {
}

ScatteringByteChannel则支持根据传入偏移量读,支持根据传入偏移量写GatheringByteChannel

public interface ScatteringByteChannel extends ReadableByteChannel {
    long read(ByteBuffer[] dsts, int offset, int length) throws IOException;
    long read(ByteBuffer[] dsts) throws IOException;}
 
public interface GatheringByteChannel extends WritableByteChannel {
    long write(ByteBuffer[] srcs, int offset, int length) throws IOException;
    long write(ByteBuffer[] srcs) throws IOException;
}

TCP协议

客户端

TCP协议除了不支持组播,其他和UDP是一样的,不再重复介绍。

服务端

服务端无需数据读写,仅需要接收连接,数据读写是SocketChannel干的事。因此没有ReadableByteChannelWriteableByteChannel等读写接口

文件

文件比网络协议少了NetworkChannelSelChImplSelectableChannelSelChImplSelectableChannel主要是用于支持选择器的,由于网络传输大多数连接时空闲的,而且数据何时会到来并不知晓,同时需要支持高并发来连接,因此支持多路复用技术可以显著的提高性能,而磁盘读写则没有该需求,因此无需选择器。

SeekableByteChannel可以通过修改position支持从指定位置读写数据。

public interface SeekableByteChannel extends ByteChannel {
    int read(ByteBuffer dst) throws IOException;
 
    int write(ByteBuffer src) throws IOException;
    
    long position() throws IOException;
    //设置偏移量
    SeekableByteChannel position(long newPosition) throws IOException;
 
    long size() throws IOException;
    //截取指定大小
    SeekableByteChannel truncate(long size) throws IOException;
}

总结

由于文章篇幅比较长,因此还是将接口分析和实现分析分开。本篇文章对Channel的接口进行说明,下一篇将对具体的实现进行分析。

相关文章
|
2月前
muduo源码剖析之channel通道类
channel是muduo中的事件分发器,它只属于一个EventLoop,Channel类中保存着IO事件的类型以及对应的回调函数,每个channel只负责一个文件描述符,但它并不拥有这个文件描述符。channel是在epoll和TcpConnection之间起沟通作用,故也叫做通道,其它类通过调用channel的setCallbcak来和建立channel沟通关系。
46 0
|
2月前
|
缓存 Java API
【Netty 网络通信】Channel 接口解析
【1月更文挑战第9天】【Netty 网络通信】Channel 接口解析
|
缓存 网络协议 Java
Java NIO学习(二):Channel通道
Java NIO 的通道类似流,但又有些不同:
147 0
Java NIO学习(二):Channel通道
|
Java API
NIO学习三-Channel
在学习NIO时,ByteBuffer、Channel、Selector三个组件是必须了解的。前面我们说到ByteBuffer是作为缓冲区进行数据的存放或者获取。通常我们需要进行flip翻转操作,但是这个在Netty中,有一个更为强大的类可以替代ByteBuf,其不需要进行翻转,也可以进行读写的双向操作。要将数据打包到缓冲区中,通常需要使用通道,而通道作为传输数据的载体,也即它可以使数据从一端到另一端,因此就必须进行了解。 Channel中,我们也看到其子类有很多,通常都是用于读写操作的。其中ByteChannel可以进行读写操作,也即可以进行双向操作。 操作过程:首先创建流对象,有了流对象获取
66 0
NIO学习三-Channel
|
设计模式 缓存 网络协议
Netty4 Channel 概述(通道篇)
Netty4 Channel 概述(通道篇)
Netty4 Channel 概述(通道篇)
|
缓存 前端开发 网络协议
Netty4 ChannelHandler 概述(通道篇)
Netty4 ChannelHandler 概述(通道篇)
Netty4 ChannelHandler 概述(通道篇)
|
存储 网络协议 Unix
netty系列之:netty中各不同种类的channel详解
netty系列之:netty中各不同种类的channel详解
netty系列之:netty中各不同种类的channel详解
J3
|
Java API
详解,NIO中的通道(Channel)
这是 IO 相关的第三篇通道,主要讲解一下通道是什么,在 Java NIO 中的体系及使用。能被称为 NIO 中的三大组件之一作用肯定是不言而喻的,所以对于通道的掌握还是很重要的,那我们往下看把!
J3
251 0
详解,NIO中的通道(Channel)
【Netty】NIO 通道 ( Channel ) 组件(二)
【Netty】NIO 通道 ( Channel ) 组件(二)
175 0
【Netty】NIO 通道 ( Channel ) 组件(二)