
4.3 可中断套接字
当连接到一个套接字时,当前线程将会被阻塞直到建立连接或产生超时为止。同样地,当通过套接字读写数据时,当前线程也会被阻塞直到操作成功或产生超时为止。
在交互式的应用中,也许会考虑为用户提供一个选项,用以取消那些看似不会产生结果的连接。但是,当线程因套接字无法响应而发生阻塞时,则无法通过调用interrupt来解除阻塞。
为了中断套接字操作,可以使用java.nio包提供的一个特性——SocketChannel类。可以使用如下方法打开SocketChannel:

通道(channel)并没有与之相关联的流。实际上,它所拥有的read和write方法都是通过使用Buffer对象来实现的(关于NIO缓冲区的相关信息请参见第2章)。ReadableByteChannel接口和WritableByteChannel接口都声明了这两个方法。
如果不想处理缓冲区,可以使用Scanner类从SocketChannel中读取信息,因为Scanner有一个带ReadableByteChannel参数的构造器:

通过调用静态方法Channels.newOutputStream,可以将通道转换成输出流。

上述操作就是所有要做的事情。当线程正在执行打开、读取或写入操作时,如果线程发生中断,那么这些操作将不会陷入阻塞,而是以抛出异常的方式结束。
程序清单4-5的程序对比了可中断套接字和阻塞套接字:服务器将连续发送数字,并在每发送十个数字之后停滞一下。点击两个按钮中的任何一个,都会启动一个线程来连接服务器并打印输出。第一个线程使用可中断套接字,而第二个线程使用阻塞套接字。如果在第一批的十个数字的读取过程中点击“Cancel”按钮,这两个线程都会中断。
程序清单4-5 interruptible/InterruptibleSocketTest.java






但是,在第一批十个数字之后,就只能中断第一个线程了,第二个线程将保持阻塞直到服务器最终关闭连接(参见图4-6)。

图4-6 中断一个套接字
java.net.InetSocketAddress 1.4
·InetSocketAddress(String hostname,int port)
用给定的主机和端口参数创建一个地址对象,并在创建过程中解析主机名。如果主机名不能被解析,那么该地址对象的unresolved属性将被设为true。
·boolean isUnresolved()
如果不能解析该地址对象,则返回true。
java.nio.channels.SocketChannel 1.4
·static SocketChannel open(SocketAddress address)
打开一个套接字通道,并将其连接到远程地址。
java.nio.channels.Channels 1.4
·static InputStream newInputStream(ReadableByteChannel channel)
创建一个输入流,用以从指定的通道读取数据。
·static OutputStream newOutputStream(WritableByteChannel channel)
创建一个输出流,用以向指定的通道写入数据。