java.nio.channels
public abstract class SocketChannel extends AbstractSelectableChannel implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannel
SocketChannel可看作是Socket的替代类,但它比Scoket具有更多的功能。
SocketChannel不仅从SelectableChannel父类中继承了configureBlocking()和register()方法,而且实现了ByteChannel接口,因此具有读写数据的read(Buffer dst)和write(Buffer src)方法。
SocketChannel没有public类型的构造方法,必须通过它的静态方法open()来创建SocketChannel对象。
SocketChannel是一个连接到TCP网络套接字的通道。可以通过以下两种方式创建SocketChannel:
- 打开一个SocketChannel并连接到互联网上的某台服务器
- 一个新连接到达ServerSocketChannel时,会创建一个SocketChannel
SocketChannel的主要方法如下:
- open(), open(SocketAddress remote) —— 静态工厂方法负责创建SocketChannel对象,
SocketChannel socketChannel = SocketChannel.open();
channel.connect(remote);
等价于:
SocketChannel socketChannel = SocketChannel.open(remote);
- close() —— 关闭SocketChannel
- validOps() —— 返回SocketChannel所能产生的事件,这个方法总是返回以下值: SelectionKey.OP_CONNECT | Selection.OP_READ | SelectionKey.OP_WRITE
- socket() —— 返回与这个SocketChannel关联的Socket对象,每个SocketChannel对象都与一个Socket对象关联
- isConnected() —— 判断底层Socket()是否已经建立了远程连接
- isConnectionPending() —— 判断是否正在进行远程连接,当远程连接已经开始,但还没有完成时,返回true,否则返回false
- connect(SocketAddress remote) —— 使底层Socket建立远程连接。当SocketChannel处于非阻塞模式时,如果立即连接成功,该方法返回true,如果不能立即成功连接,返回false,程序过会必须通过调用finishConnect()方法来完成连接。当SocketChannel处于阻塞模式,如果立即连接成功,该方法返回true,如果不能立即连接成功,将进入阻塞状态,直到连接成功,或者出现I/O异常
- finishConnect() —— 试图完成连接远程服务器的操作。在非阻塞模式下,建立连接从调用SocketChannel的connect()方法开始,到调用finishConnect()结束。如果finishConnect()方法顺利完成连接,或者在调用此方法之前连接已经建立,则finishConnect()方法立即返回true。如果连接操作还没完成,则立即返回false;如果连接操作中遇到异常而失败,则抛出相应的I/O异常。在阻塞模式下,如果连接操作没有完成,则会进入阻塞状态,直到连接完成,或者出现I/O异常
- read(ByteBuffer dst) —— 从Channel中读入若干字节,把它们存放到参数指定的ByteBuffer中。假定执行read()方法前,ByteBuffer的位置为p,剩余容量为r,r等于dst,remaining()方法的返回值。假定read()方法实际上读入了n个字节,read()方法返回后,参数dst引用的ByteBuffer的位置变为p+n,极限保持不变。
- 在阻塞模式下,read()方法会争取读取到r个字节,如果输入流中不足r个字节,就进入阻塞状态,直到读入r个字节,或者读到了输入流末尾,或者出现了I/O异常
- 在非阻塞模式下,read()方法奉行能读到多少数据就读多少数据的元素。read()方法读取当前通道中的可读数据,有可能不足r个字节,或者为0个直接,read()方法总是立即返回,而不会等到读取了r个字节再返回。
- read()方法返回实际上读入的字节数,有可能为0.如果返回-1,就表示读到了输入流的末尾。
- write(ByteBuffer src) —— 把参数src指定的ByteBuffer中的字节写到Channel中。假定执行write()方法前,ByteBuffer的位置为p,剩余容量为r,r等于src.remaining()方法的返回值。假定write()方法实际上相通道中写入了n个字节,write()方法返回后,参数src引用的ByteBuffer的位置变为p+n,极限保持不变。
- 在阻塞模式下,wirte()方法会争取输出r个字节,如果底层网络的输出缓冲区不能容纳r个字节,就进入阻塞状态,直到输出了r个字节,或者出现了I/O异常
- 在非阻塞模式下,write()方法奉行能输出多少数据就输出多少数据的原则,有可能不足r个字节,或者为0个字节,write()方法总是立即返回,而不会等到输出r个字节后在返回
- write(0方法返回实际上输出的字节数,有可能为0
从SocketChannel读取数据
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = socketChannel.read(buf);
read()方法返回的int值表示读了多少字节进Buffer里。如果返回的是-1.表示已经读到了流的末尾(连接关闭了)。
非阻塞模式下,read()方法在尚未读取到任何数据时可能就返回了。所以需要关注它的int返回值,它会告诉你读取了多少字节。
写入SocketChannel —— 非阻塞模式 ***
String newData = ... ...
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()){
chaneel.write(buf);
}
SocketChannel.write()方法的调用是在一个while循环中的。write()方法无法保证能写多少字节到SocketChannel中,所以,需要重复调用write()直到Buffer没有要写的字节为止。
建立连接 —— 非阻塞模式
如果SocketChannel在非阻塞模式下,此时掉哟过connect(),该方法可能在建立连接之前就返回了,为了确定连接是否建立,可以调用finishConnect()方法,
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("http://...", 80));
while (!socketChannel.finishConnect()){
// wait, or do something else...
}