Java NIO 之 Socket Channel
Posted luojiahu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java NIO 之 Socket Channel相关的知识,希望对你有一定的参考价值。
在Java NIO中用Channel来对程序与进行I/O操作主体的连接关系进行抽象,这些IO主体包括如文件、Socket或其他设备。简而言之,指代了一种与IO操作对象间的连接关系。
按照Channel接口的定义,Channel只有open和closed两种状态,只有在channel处于open状态下对其操作时才有效,而对closed的channel进行操作会导致抛出异常。相应的Channel接口也仅有isOpen()和close()两种方法。
在Socket编程中,常用的Channel类是ServerSocketChannel和SocketChannel。ServerSocketChannel表示作为Socket服务端,处于监听状态的Socket连接。而SocketChannel表示一个已经建立的Socket连接。
ServerSocketChannel具有accept()方法,当该方法成功返回时,会返回一个已经建立的SocketChannle对象,这也表示了这两种代表不同状态的Socket Channel间的联系和区别。ServerSocketChannel通过bind()方法绑定到本地地址,并且可以通过setOption()方法设置SO_RCVBUF(Socket接收缓冲区大小)和SO_REUSEADDR(是否重用Socket地址,由于Socket在关闭时需要经过多个状态的变迁,这个选项通常在需要快速重启的场景下有用)两个Socket选项。
SocketChannel采用connet()方法建立连接,并且支持非阻塞式建立,在非阻塞状态下连接的最终建立状态通过isConnetionPending()和finishConnect()进行组合判断。SocketChannel同时支持异步关闭,若写线程主动关闭了Channel,则并发的读操作将读取不到内容;若读线程主动关闭了Channel,则并发的写操作将得到AsynchronousCloseException。同样的对SocketChannle可以通过setOption()方法设置若干选项,包括:SO_SNDBUF(发送缓冲区), SO_RCVBUF, SO_KEEPALIVE(是否采用协议栈实现的保活机制,默认为FALSE), SO_REUSEADDR, SO_LINGER(阻塞式连接下的关闭等待时长), TCP_NODELAY(是否禁用Nagle算法)。
这两个类涉及的相关类图如下图所示:
可见,ServerSocketChannel和SocketChannel均继承了SelectableChannel以支持与Selector配合实现非阻塞式IO。SocketChannel继承了若干支持读写操作的Channel以支持读写操作。
另外,Channel的读写需要借助于Buffer,可见在NIO中Buffer是程序中其他对象与Channel交互的中介,通过Buffer和Channel的配合实现对I/O对象的读写操作。
几个关键的接口定义如下
public interface Channel { /** * 判断是否开启 * @return */ public boolean isOpen(); public void close() throws IOException; } /** * 可中断Channel</p> * 1. 可被异步关闭. 若当前线程阻塞于Channel的读写操作,</l> * 当另一线程调用close操作后,当前线程会收到一个AsynchronousCloseException</p> * * 2. 可中断. 若当前线程阻塞于Channel,当其他线程触发interrupt方法时</l> * 会导致Channel Close,当前线程收到一个ClosedByInterruptException, * 其interrupt状态被设置</p> * * 3. 若当前线程interrupt状态已被设置,当调用当前Channel的阻塞IO操作时,</l> * channel会被close,线程会收到ClosedByInterruptException. </l> * 其interrupt状态保持不变.</p> * * @author luojiahu * */ public interface InterruptibleChannel extends Channel{ public void close() throws IOException; } /** * 可读Byte Channel * 可对当前Channel阻塞读. 若有其他线程正对当前Channel进行读操作,</l> * 调用read会一直阻塞至其他上一读操作完成。 * * @author luojiahu * */ public interface ReadableByteChannel extends Channel { /** * 从当前Channel中读取内容写入Buffer</l> * 是否能够读入内容,取决于当前Channel的状态.</l> * 如,对于一个非阻塞的Socket Channel,如果当前socket的</l> * 接收缓冲区没有任何内容,则不能写入任何内容到src * @param src * @return * @throws IOException */ public int read(ByteBuffer src) throws IOException; } /** * 可写Byte Channel * 可对当前Channel阻塞写.</l> * @author luojiahu * */ public interface WritableByteChannel extends Channel { /** * 从dst buffer中读取内容写入当前Channel</l> * 是否能够写入内容取决于当前Channel的状态</l> * 如对于非阻塞 Socket Channel,只能写入不大于</l> * 对应写入缓冲区可写大小的内容 * * @param dst * @throws IOException */ public void write(ByteBuffer dst) throws IOException; } /** * 网络socket channel</l> * @author luojiahu * */ public interface NetWorkChannel extends Channel{ /** * 绑定到本地地址</l> * 一旦绑定,则绑定直至通道关闭</l> * 如果参数未空,则绑定至自动分配的地址 * @param local * @return * @throws IOException */ NetWorkChannel bind(SocketAddress local) throws IOException; /** * 获取绑定的本地地址 * @return * @throws IOException */ SocketAddress getLocalAddress() throws IOException; /** * 设定socket 选项 * @param name * @param value * @return * @throws IOException */ <T> NetworkChannel setOption(SocketOption<T> name, T value) throws IOException; }
以上是关于Java NIO 之 Socket Channel的主要内容,如果未能解决你的问题,请参考以下文章