![Java核心技术·卷Ⅱ:高级特性(原书第10版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/937/34339937/b_34339937.jpg)
4.3 可中断套接字
当连接到一个套接字时,当前线程将会被阻塞直到建立连接或产生超时为止。同样地,当通过套接字读写数据时,当前线程也会被阻塞直到操作成功或产生超时为止。
在交互式的应用中,也许会考虑为用户提供一个选项,用以取消那些看似不会产生结果的连接。但是,当线程因套接字无法响应而发生阻塞时,则无法通过调用interrupt来解除阻塞。
为了中断套接字操作,可以使用java.nio包提供的一个特性——SocketChannel类。可以使用如下方法打开SocketChannel:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/205-i.jpg?sign=1738825951-cwmMmWqLaeNB1AaDxG5qgkoOMnE4JniP-0-ed38ff4cc7f08581b2a2b33ba393d470)
通道(channel)并没有与之相关联的流。实际上,它所拥有的read和write方法都是通过使用Buffer对象来实现的(关于NIO缓冲区的相关信息请参见第2章)。ReadableByteChannel接口和WritableByteChannel接口都声明了这两个方法。
如果不想处理缓冲区,可以使用Scanner类从SocketChannel中读取信息,因为Scanner有一个带ReadableByteChannel参数的构造器:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/205-2-i.jpg?sign=1738825951-WAAU2wGQLtCmd9PJsOapKZdjnJTP4z3G-0-c896dd8b29ba0a0e41032b2f77636902)
通过调用静态方法Channels.newOutputStream,可以将通道转换成输出流。
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/205-3-i.jpg?sign=1738825951-N7amYfEea1oSrTa3uopjotT9xGNCN5gv-0-e8f2835baa51fe19f3d1f450c0172081)
上述操作就是所有要做的事情。当线程正在执行打开、读取或写入操作时,如果线程发生中断,那么这些操作将不会陷入阻塞,而是以抛出异常的方式结束。
程序清单4-5的程序对比了可中断套接字和阻塞套接字:服务器将连续发送数字,并在每发送十个数字之后停滞一下。点击两个按钮中的任何一个,都会启动一个线程来连接服务器并打印输出。第一个线程使用可中断套接字,而第二个线程使用阻塞套接字。如果在第一批的十个数字的读取过程中点击“Cancel”按钮,这两个线程都会中断。
程序清单4-5 interruptible/InterruptibleSocketTest.java
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/205-4-i.jpg?sign=1738825951-zdY6dH1pf3fuVHgWOeS7pypzKu8YGLNp-0-7dedc9e092e067e1ebe200855adbab95)
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/206-i.jpg?sign=1738825951-sZpiVOOz0iYbVSFK3Os6pCENcM6fQlEt-0-6a12ab54eb75b5265d312bd7623dd3f4)
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/207-i.jpg?sign=1738825951-rkeDO67iQoeZIqBmkDs1kGIXaLIRr9PR-0-a6d8df8b339b1c5347d0a71a159ca5e5)
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/208-i.jpg?sign=1738825951-Qq4jrTfs2Z1vlt4y3PKElYVzDt9Y7WYf-0-01eb0596784afe5d1bc9bc2a23827e18)
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/209-i.jpg?sign=1738825951-VVlo9jAVdleN7VJbTGy7t575vAHXpPoG-0-296863f999b5c0a32d77df73a261d7e5)
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/210-i.jpg?sign=1738825951-R4uL7w8IsEWsc3DNfCuW0HDuBVkI5RSy-0-db48fece204a600badc34e4ab8f522be)
但是,在第一批十个数字之后,就只能中断第一个线程了,第二个线程将保持阻塞直到服务器最终关闭连接(参见图4-6)。
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/4a6-i.jpg?sign=1738825951-QShy2m64ypCGh6RjgvrZYYk6ZlKoQ8bR-0-524f87e450d8600d27ab7b65bc8a7996)
图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)
创建一个输出流,用以向指定的通道写入数据。