SocketChannel类可以读写TCP Socket。数据的读写必须以ByteBuffer的形式。
连接
SocketChannel提供了静态的open方法来创建新的SocketChannel对象:
public static SocketChannel open() throws IOException {
return SelectorProvider.provider().openSocketChannel();
}
public static SocketChannel open(SocketAddress remote)
throws IOException
{
SocketChannel sc = open();
try {
sc.connect(remote);
} catch (Throwable x) {
try {
sc.close();
} catch (Throwable suppressed) {
x.addSuppressed(suppressed);
}
throw x;
}
assert sc.isConnected();
return sc;
}
这是两个open方法,第一个方法只会创建一个Channel但是不会进行连接,之后必须用connect方法来进行连接。第二个方法接收一个SocketAddress用来指定要连接的机器和端口号,它会进行连接,因此会阻塞,在连接成功建立或者抛出异常之前,这个方法不会返回。
以非阻塞方式建立连接
当我们需要对socket的选项进行配置或者对通道进行配置时,最好选择上面说的第一种方式。特别是当我们需要以非阻塞方式来打开通道时:
public static void main(String[] args) throws IOException {
SocketChannel socketChannel = SocketChannel.open();
SocketAddress socketAddress = new InetSocketAddress("www.cafeaulait.org", 80);
socketChannel.configureBlocking(false);
socketChannel.connect(socketAddress);
}
configureBlocking方法用来设置是否阻塞。当设置为非阻塞时,connect方法会立即返回,甚至在连接建立之前就返回。
使用finishConnect方法
在非阻塞模式下,在使用连接之前,我们必须调用finishConnect()方法来完成连接。这个方法只对非阻塞模式是必需的,如果连接现在可用,finishConnect会返回true,如果连接还没建立,会返回false,如果连接无法建立,会抛出异常。如果当前是阻塞模式,那么这个方法就会被阻塞,直到连接成功或者失败,这时候就要么返回true要么抛出异常。
获取连接的状态
我们可以调用isConnected和isConnectionPending方法来获取连接是否成功或者还未完成。
/**
* Tells whether or not this channel's network socket is connected.
*
* @return <tt>true</tt> if, and only if, this channel's network socket
* is {@link #isOpen open} and connected
*/
public abstract boolean isConnected();
/**
* Tells whether or not a connection operation is in progress on this
* channel.
*
* @return <tt>true</tt> if, and only if, a connection operation has been
* initiated on this channel but not yet completed by invoking the
* {@link #finishConnect finishConnect} method
*/
public abstract boolean isConnectionPending();
写入数据
channel连接建立成功之后,我们就可以向通道写入或者从通道读取数据了,有以下方法可以完成读写操作:
读取到单个ByteBuffer
我们先来看read方法:
/**
* @throws NotYetConnectedException
* If this channel is not yet connected
*/
public abstract int read(ByteBuffer dst) throws IOException;
读取到多个ByteBuffer
后面的两个方法读取channel中的数据到一个ByteBuffer数组:
public abstract long read(ByteBuffer[] dsts, int offset, int length)
throws IOException;
/**
* @throws NotYetConnectedException
* If this channel is not yet connected
*/
public final long read(ByteBuffer[] dsts) throws IOException {
return read(dsts, 0, dsts.length);
}
写入数据
写入数据与读取数据一样,也支持从一个缓冲区写入和从多个缓冲区写入:
/**
* @throws NotYetConnectedException
* If this channel is not yet connected
*/
public abstract int write(ByteBuffer src) throws IOException;
/**
* @throws NotYetConnectedException
* If this channel is not yet connected
*/
public abstract long write(ByteBuffer[] srcs, int offset, int length)
throws IOException;
/**
* @throws NotYetConnectedException
* If this channel is not yet connected
*/
public final long write(ByteBuffer[] srcs) throws IOException {
return write(srcs, 0, srcs.length);
}
关闭channel
我们可以直接使用close()方法来关闭channel。