![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=1738906512-t1oi7euRbmxLdRJZGekRbTXUkaA3D998-0-af5743899750d4bea55cde7483f57350)
通道(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=1738906512-TPXZwYZXpjM7bLDsN8X4KQRAF9sZb6M1-0-3135a0848a324d447aae92db1097a7b4)
通过调用静态方法Channels.newOutputStream,可以将通道转换成输出流。
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/205-3-i.jpg?sign=1738906512-eOd0CPKWFBCXSalVXxnSOjHh48VLHGZo-0-2cd7acedf1083fa8211a262b3873fb1c)
上述操作就是所有要做的事情。当线程正在执行打开、读取或写入操作时,如果线程发生中断,那么这些操作将不会陷入阻塞,而是以抛出异常的方式结束。
程序清单4-5的程序对比了可中断套接字和阻塞套接字:服务器将连续发送数字,并在每发送十个数字之后停滞一下。点击两个按钮中的任何一个,都会启动一个线程来连接服务器并打印输出。第一个线程使用可中断套接字,而第二个线程使用阻塞套接字。如果在第一批的十个数字的读取过程中点击“Cancel”按钮,这两个线程都会中断。
程序清单4-5 interruptible/InterruptibleSocketTest.java
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/205-4-i.jpg?sign=1738906512-dioMe9jCuC9sb1FsxTP8A9qKGwQuaFwW-0-0b98890538fd70255556540b29ddcee5)
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/206-i.jpg?sign=1738906512-GSL7ttse2btzGlcvLDsPqjMsDgXqNw8z-0-290a58ed84bac84b42bde032b50f95a1)
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/207-i.jpg?sign=1738906512-EULaAE4Drb5ja0mRqtgVGgXkpFKH6VRV-0-07d3833841a46461a3562091cf8855f7)
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/208-i.jpg?sign=1738906512-uumfZQFXpRmKBMOjuLHCfgZecia5HBqV-0-fa9379ea66c3c1c7e205ce1256775a26)
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/209-i.jpg?sign=1738906512-l9nnOBT3W2HFIzrAVbNFNinl4ARpiUge-0-5e45384a03b80700f5e18ee099b47f7f)
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/210-i.jpg?sign=1738906512-GGiqO1zqNt7sN9eoyRJGgr2fKmq5efG0-0-dded9914e38f0f740e406e76d5968b90)
但是,在第一批十个数字之后,就只能中断第一个线程了,第二个线程将保持阻塞直到服务器最终关闭连接(参见图4-6)。
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/4a6-i.jpg?sign=1738906512-ch5ETFKX54rjNQ5thFKAq200D7OtWI83-0-32ba5ec06d055074236fb1b688bebd58)
图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)
创建一个输出流,用以向指定的通道写入数据。