【Java.NIO】API —— Channel接口 —— SocketChannel类

来源:互联网 发布:数据分析方法梅长林 编辑:程序博客网 时间:2024/04/29 13:11
java.nio.channelspublic 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...}




0 0