Java Nio 十四

2017/05/27 Java

Java NIO 十四

SocketChannel

它是使用最多的 socket 通道类,部分类签名如下:


public abstract class SocketChannel
    extends AbstractSelectableChannel
    implements ByteChannel, ScatteringByteChannel, GatheringByteChannel
{
    // This is a partial API listing
    public static SocketChannel open( ) throws IOException
    public static SocketChannel open (InetSocketAddress remote)
    throws IOException
    public abstract Socket socket( );
    public abstract boolean connect (SocketAddress remote)
    throws IOException;
    public abstract boolean isConnectionPending( );
    public abstract boolean finishConnect( ) throws IOException;
    public abstract boolean isConnected( );
    public final int validOps( )
}

Socket 和 SocketChannel 类封装点对点、有序的网络连接,类似于 TCP/IP 网络连接。SocketChannel 扮演客户端发起同一个监听服务器的连接。直到连接成功,它才能收到数据并且只会从连接到的地址接收。

每个 SocketChannel 对象创建时都是同一个对等的 java.net.Socket 对象串联的。静态的 open( )方法可以创建一个新的 SocketChannel 对象,而在新创建的 SocketChannel 上调用 socket()方法能返回 它对等的 Socket 对象;在该 Socket 上调用 getChannel( )方法则能返回最初的那个 SocketChannel。

虽然每个 SocketChannel 对象都会创建一个对等的 Socket 对象,反过来却不成立。直接创建的 Socket 对象不会关联 SocketChannel 对象,它们的 getChannel( )方法只返回 null。

新创建的 SocketChannel 虽已打开却是未连接的。在一个未连接的 SocketChannel 对象上尝试一 个 I/O 操作会导致 NotYetConnectedException 异常。我们可以通过在通道上直接调用 connect( )方法 或在通道关联的 Socket 对象上调用 connect( )来将该 socket 通道连接。一旦一个 socket 通道被连 接,它将保持连接状态直到被关闭。可以通过调用布尔型的 isConnected() 方法来测试某个 SocketChannel 当前是否已连接。

在 SocketChannel 上并没有一种 connect( )方法可以指定超时(timeout)值,当 connect( )方 法在非阻塞模式下被调用时 SocketChannel 提供并发连接:它发起对请求地址的连接并且立即返回 值。如果返回值是 true,说明连接立即建立了(这可能是本地环回连接);如果连接不能立即建 立,connect( )方法会返回false且并发地继续连接建立过程。

面向流的的 socket 建立连接状态需要一定的时间,因为两个待连接系统之间必须进行包对话以 建立维护流 socket 所需的状态信息。跨越开放互联网连接到远程系统会特别耗时。假如某个 SocketChannel 上当前正由一个并发连接,isConnectPending( )方法就会返回 true 值。

调用 finishConnect( )方法来完成连接过程,该方法任何时候都可以安全地进行调用。假如在一 个非阻塞模式的 SocketChannel 对象上调用 finishConnect( )方法,将可能出现下列情形之一:

  • connect( )方法尚未被调用。那么将产生 NoConnectionPendingException 异常。
  • 连接建立过程正在进行,尚未完成。那么什么都不会发生,finishConnect( )方法会立即返回false 值。
  • 在非阻塞模式下调用connect( )方法之后,SocketChannel又被切换回了阻塞模式。那么如果有必要的话,调用线程会阻塞直到连接建立完成,finishConnect( )方法接着就会返回true值。
  • 在初次调用 connect( )或最后一次调用 finishConnect( )之后,连接建立过程已经完成。那么SocketChannel 对象的内部状态将被更新到已连接状态,finishConnect( )方法会返回 true值,然后 SocketChannel 对象就可以被用来传输数据了。
  • 连接已经建立。那么什么都不会发生,finishConnect( )方法会返回 true 值。

当通道处于中间的连接等待(connection-pending)状态时,只能调用 finishConnect( )isConnectPending( )isConnected( )方法。一旦连接建立过程成功完成,isConnected( )将返回 true 值。

如果尝试异步连接失败,那么下次调用 finishConnect( )方法会产生一个适当的经检查的异常以 指出问题的性质。通道然后就会被关闭并将不能被连接或再次使用。

Socket 通道是线程安全的。并发访问时无需特别措施来保护发起访问的多个线程,不过任何时 候都只有一个读操作和一个写操作在进行中。请记住,sockets 是面向流的而非包导向的。它们可 以保证发送的字节会按照顺序到达但无法承诺维持字节分组。

connect( )finishConnect( )方法是互相同步的,并且只要其中一个操作正在进行,任何读或写 的方法调用都会阻塞,即使是在非阻塞模式下。

Show Disqus Comments

Search

    Table of Contents