天天看点

SocketChannel类

随时随地阅读更多技术实战干货,获取项目源码、学习资料,请关注源代码社区公众号(ydmsq666)、QQ技术交流群(183198395)。

SocketChannel类
SocketChannel类
SocketChannel类

一、简介

该类表示针对面向流的连接套接字的可选择通道。

类声明:public abstract class SocketChannel extends AbstractSelectableChannel implements ByteChannel, ScatteringByteChannel, GatheringByteChannel

类层次:

SocketChannel类

套接字通道不是连接网络套接字的完整抽象。必须通过调用

socket

() 方法所获得的关联

Socket

对象来完成对套接字选项的绑定、关闭和操作。不可能为任意的已有套接字创建通道,也不可能指定与套接字通道关联的套接字所使用的

SocketImpl

对象。

通过调用此类的某个

open()

方法创建套接字通道。新创建的套接字通道已打开,但尚未连接。试图在未连接的通道上调用 I/O 操作将导致抛出

NotYetConnectedException

。可通过调用套接字通道的

connect

方法连接该通道;一旦连接后,关闭套接字通道之前它会一直保持已连接状态。可通过调用套接字通道的

isConnected

方法来确定套接字通道是否已连接。

套接字通道支持非阻塞连接:可创建一个套接字通道,并且通过

connect

方法可以发起到远程套接字的连接,之后通过

finishConnect

方法完成该连接。可通过调用

isConnectionPending

方法来确定是否正在进行连接操作。

可单独地关闭 套接字通道的输入端和输出端,而无需实际关闭该通道。调用关联套接字对象的

shutdownInput

方法来关闭某个通道的输入端将导致该通道上的后续读取操作返回 -1(指示流的末尾)。调用关联套接字对象的

shutdownOutput

方法来关闭通道的输出端将导致该通道上的后续写入操作抛出

ClosedChannelException

套接字通道支持异步关闭,这与

Channel

类中所指定的异步 close 操作类似。如果一个线程关闭了某个套接字的输入端,而同时另一个线程被阻塞在该套接字通道上的读取操作中,那么处于阻塞线程中的读取操作将完成,而不读取任何字节且返回 -1。I如果一个线程关闭了某个套接字的输出端,而同时另一个线程被阻塞在该套接字通道上的写入操作中,那么阻塞线程将收到

AsynchronousCloseException

多个并发线程可安全地使用套接字通道。尽管在任意给定时刻最多只能有一个线程进行读取和写入操作,但数据报通道支持并发的读写。

connect

finishConnect

方法是相互同步的,如果正在调用其中某个方法的同时试图发起读取或写入操作,则在该调用完成之前该操作被阻塞。

二、构造方法

protected SocketChannel(SelectorProvider provider)   初始化此类的一个新实例。
           
三、方法详解  
           
①public static SocketChannel open()throws IOException  打开套接字通道。
           

通过调用系统级默认

SelectorProvider

对象的

openSocketChannel

方法来创建新的通道。 返回新的套接字通道

抛出:

IOException

- 如果发生 I/O 错误

②public static SocketChannel open(SocketAddress remote)throws IOException  打开套接字通道并将其连接到远程地址。
           
这种便捷方法的工作方式就像以下过程一样:调用          open()                 方法、在得到的套接字通道上调用          connect                 方法、向其传递 remote,然后返回该通道。      

参数:

remote

- 与新通道连接的远程地址

抛出:

AsynchronousCloseException

- 如果正在进行连接操作时另一个线程关闭了此通道

ClosedByInterruptException

- 如果正在进行连接操作时另一个线程中断了当前线程,因此关闭了该通道并将当前线程设置为中断状态    

UnresolvedAddressException

- 如果无法完全解析给定的远程地址

     UnsupportedAddressTypeException

- 如果不支持给定的远程地址类型

     SecurityException

- 如果已安装安全管理器并且它不允许对给定远程端点进行访问

     IOException

- 如果发生其他 I/O 错误

③public final int validOps()  返回一个操作集,标识此通道所支持的操作。套接字通道支持连接、读取和写入,所以此方法返回 (

SelectionKey.OP_CONNECT

SelectionKey.OP_READ

SelectionKey.OP_WRITE

)

指定者:类

SelectableChannel

中的

validOps

返回:有效操作集

④ public abstract Socket socket()   获取与此通道关联的套接字。返回的对象不会声明任何在

Socket

类中未声明的公共方法。

⑤public abstract boolean isConnected()   判断是否已连接此通道的网络套接字。

⑥public abstract boolean isConnectionPending()  判断此通道上是否正在进行连接操作。

返回:当且仅当已在此通道上发起连接操作,但是尚未通过调用

finishConnect

方法完成连接时才返回 true

⑦public abstract boolean connect(SocketAddress remote)throws IOException  连接此通道的套接字。

如果此通道处于非阻塞模式,则调用此方法会发起一个非阻塞连接操作。如果立即建立连接(使用本地连接时就是如此),则此方法返回 true。否则此方法返回 false,并且必须在以后通过调用

finishConnect

方法来完成该连接操作。

如果此通道处于阻塞模式,则在建立连接或发生 I/O 错误之前将阻塞此方法的调用。

此方法执行与

Socket

类完全相同的安全检查。也就是说,如果已安装了安全管理器,则此方法验证其

checkConnect

方法是否允许连接到给定远程端点的地址和端口号。

可在任意时间调用此方法。如果正在调用此方法时在此通道上调用读取或写入操作,则在此调用完成前将首先阻塞该操作。如果试图发起连接但失败了,也就是说如果调用此方法抛出经过检查的异常,则关闭此通道。

返回:如果已建立连接,则返回 true,如果此通道处于非阻塞模式并且正在进行连接操作,则返回 false

抛出:

AlreadyConnectedException

- 如果已连接此通道

ConnectionPendingException

- 如果已在此通道上进行非阻塞连接操作

ClosedChannelException

- 如果此通道已关闭

AsynchronousCloseException

- 如果正在进行连接操作时另一个线程关闭了此通道

ClosedByInterruptException

- 如果正在进行连接操作时另一个线程中断了当前线程,因此关闭了该通道并将当前线程设置为中断状态

UnresolvedAddressException

- 如果没有完全解析给定的远程地址

UnsupportedAddressTypeException

- 如果不支持给定的远程地址类型

SecurityException

- 如果已安装安全管理器并且它不允许对给定远程端点进行访问

IOException

- 如果发生其他 I/O 错误

⑧public abstract boolean finishConnect()throws IOException  完成套接字通道的连接过程。

通过将套接字通道置于非阻塞模式,然后调用其

connect

方法来发起非阻塞连接操作。一旦建立了连接,或者尝试已失败,该套接字通道就变为可连接的,并且可调用此方法完成连接序列。如果连接操作失败,则调用此方法将导致抛出合适的

IOException

如果已连接了此通道,则不阻塞此方法并且立即返回 true。如果此通道处于非阻塞模式,那么当连接过程尚未完成时,此方法将返回 false。如果此通道处于阻塞模式,则在连接完成或失败之前将阻塞此方法,并且总是返回 true 或抛出描述该失败的、经过检查的异常

可在任意时间调用此方法。如果正在调用此方法时在此通道上调用读取或写入操作,则在此调用完成前将首先阻塞该操作。如果试图发起连接但失败了,也就是说如果调用此方法导致抛出经过检查的异常,则关闭此通道。

返回:当且仅当已连接此通道的套接字时才返回 true

抛出:

NoConnectionPendingException

- 如果未连接此通道并且尚未发起连接操作

ClosedChannelException

- 如果此通道已关闭

AsynchronousCloseException

- 如果正在进行连接操作时另一个线程关闭了此通道

ClosedByInterruptException

- 如果正在进行连接操作时另一个线程中断了当前线程,因此关闭了该通道并将当前线程设置为中断状态

IOException

- 如果发生其他 I/O 错误

⑨public abstract int read(ByteBuffer dst)throws IOException  将字节序列从此通道中读入给定的缓冲区。

尝试最多从该通道中读取 r 个字节,其中 r 是调用此方法时缓冲区中剩余的字节数,即 dst.remaining()。

假定读取的字节序列长度为 n,其中 0 <= n <= r。此字节序列将被传输到缓冲区中,序列中的第一个字节位于索引 p 处,最后一个字节则位于索引 p + n - 1 处,其中 p 是调用此方法时缓冲区的位置。返回时,该缓冲区的位置将等于 p + n;其限制不会更改。

读取操作可能不填充缓冲区,实际上它可能根本不读取任何字节。是否如此执行取决于通道的性质和状态。例如,处于非阻塞模式的套接字通道只能从该套接字的输入缓冲区中读取立即可用的字节;类似地,文件通道只能读取文件中剩余的字节。但是可以保证,如果某个通道处于阻塞模式,并且缓冲区中至少剩余一个字节,则在读取至少一个字节之前将阻塞此方法。

可在任意时间调用此方法。但是如果另一个线程已经在此通道上发起了一个读取操作,则在该操作完成前此方法的调用被阻塞。

指定者:接口

ReadableByteChannel

中的

read

参数:

dst

- 要向其中传输字节的缓冲区

返回:读取的字节数,可能为零,如果该通道已到达流的末尾,则返回 -1

抛出:

NotYetConnectedException

- 如果尚未连接此通道

ClosedChannelException

- 如果此通道已关闭

AsynchronousCloseException

- 如果正在进行读取操作时另一个线程关闭了此通道

ClosedByInterruptException

- 如果正在进行读取操作时另一个线程中断了当前线程,因此关闭了该通道并将当前线程设置为中断状态

IOException

- 如果发生其他 I/O 错误

⑩public abstract long read(ByteBuffer[] dsts,int offset,int length)throws IOException  将字节序列从此通道读入给定缓冲区的子序列中。

调用此方法会尝试最多从此通道读取 r 个字节,其中 r 是给定缓冲区数组的指定子序列中剩余的字节数,也就是

dsts[offset].remaining()+ dsts[offset+1].remaining()+ ... + dsts[offset+length-1].remaining()

假定读取的字节序列长度为 n,其中 0 <= n <= r。将此序列的前 dsts[offset].remaining() 个字节传输到缓冲区 dsts[offset] 中,然后将后面的 dsts[offset+1].remaining() 个字节传输到缓冲区 dsts[offset+1] 中,依此类推,直到将整个字节序列传输到给定缓冲区中。向每个缓冲区中传输尽可能多的字节,因为要保证每个已更新缓冲区(最后一个已更新缓冲区除外)的最终位置等于该缓冲区的限制。

可在任意时间调用此方法。但是如果另一个线程已经在此通道上发起了一个读取操作,则在该操作完成前此方法的调用被阻塞。

指定者:接口

ScatteringByteChannel

中的

read

参数:

dsts

- 要向其中传输字节的缓冲区

offset

- 第一个缓冲区(字节传输到该缓冲区中)在缓冲区数组中的偏移量;必须为非负数并且不能大于 dsts.length

length

- 要访问的最大缓冲区数;必须为非负数并且不能大于 dsts.length - offset

返回:读取的字节数,可能为零,如果该通道已到达流的末尾,则返回 -1

抛出:

NotYetConnectedException

- 如果尚未连接此通道

ClosedChannelException

- 如果此通道已关闭

      AsynchronousCloseException

- 如果正在进行读取操作时另一个线程关闭了此通道

ClosedByInterruptException

- 如果正在进行读取操作时另一个线程中断了当前线程,因此关闭了该通道并将当前线程设置为中断状态

      IOException

- 如果发生其他 I/O 错误

11.public final long read(ByteBuffer[] dsts) throws IOException  将字节序列从此通道读入给定的缓冲区。

调用此方法的形式为 c.read(dsts),该调用与以下调用完全相同:

c.read(dsts, 0,dsts.length);

指定者:接口

ScatteringByteChannel

中的

read

参数:

dsts

- 要向其中传输字节的缓冲区

返回:读取的字节数,可能为零,如果该通道已到达流的末尾,则返回 -1

抛出:

NotYetConnectedException

- 如果尚未连接此通道

ClosedChannelException

- 如果此通道已关闭

AsynchronousCloseException

- 如果正在进行读取操作时另一个线程关闭了此通道

ClosedByInterruptException

- 如果正在进行读取操作时另一个线程中断了当前线程,因此关闭了该通道并将当前线程设置为中断状态

IOException

- 如果发生其他 I/O 错误

12.public abstract int write(ByteBuffer src) throws IOException  将字节序列从给定的缓冲区中写入此通道。

尝试最多向该通道中写入 r 个字节,其中 r 是调用此方法时缓冲区中剩余的字节数,即 src.remaining()。

假定写入长度为 n 的字节序列,其中 0 <= n <= r。从缓冲区的索引 p 处开始传输该字节,其中 p 是调用此方法时该缓冲区的位置;最后写入的字节索引是 p + n - 1。返回时,该缓冲区的位置将等于 p + n;其限制不会更改。

除非另行指定,否则仅在写入所有请求的 r 个字节后 write 操作才会返回。有些类型的通道(取决于它们的状态)可能仅写入某些字节或者可能根本不写入。例如,处于非阻塞模式的套接字通道只能写入该套接字输出缓冲区中的字节。

可在任意时间调用此方法。但是如果另一个线程已经在此通道上发起了一个写入操作,则在该操作完成前此方法的调用被阻塞。

指定者:接口

WritableByteChannel

中的

write

参数:

src

- 要从中获取字节的缓冲区

返回:写入的字节数,可能为零

抛出:

NotYetConnectedException

- 如果尚未连接此通道

ClosedChannelException

- 如果此通道已关闭

AsynchronousCloseException

- 如果正在进行写入操作时另一个线程关闭了此通道

      ClosedByInterruptException

- 如果正在进行写入操作时另一个线程中断了当前线程,因此关闭了该通道并将当前线程的状态设置为中断

      IOException

- 如果发生其他 I/O 错误

13.public abstract long write(ByteBuffer[] srcs,int offset,int length)throws IOException  将字节序列从给定缓冲区的子序列写入此通道。

尝试最多向此通道中写入 r 个字节,其中 r 是给定缓冲区数组的指定子序列中剩余的字节数,也就是

srcs[offset].remaining() + srcs[offset+1].remaining()+ ... + srcs[offset+length-1].remaining()
           

假定写入长度为 n 的字节序列,其中 0 <= n <= r。从缓冲区 srcs[offset] 中写入此序列的前 srcs[offset].remaining() 个字节,然后从缓冲区 srcs[offset+1] 中写入后面的 srcs[offset+1].remaining() 个字节,依此类推,直到写入整个字节序列。从每个缓冲区中写入尽可能多的字节,因为要保证每个已更新缓冲区(最后一个已更新缓冲区除外)的最终位置等于该缓冲区的限制。

除非另行指定,否则仅在写入所有请求的 r 个字节后 write 操作才会返回。有些类型的通道(取决于它们的状态)可能仅写入某些字节或者可能根本不写入。例如,处于非阻塞模式的套接字通道无法写入超出该套接字输出缓冲区剩余空间的字节。

可在任意时间调用此方法。但是如果另一个线程已经在此通道上发起了一个写入操作,则在该操作完成前此方法的调用被阻塞。

指定者:接口

GatheringByteChannel

中的

write

       offset

- 第一个缓冲区(要获取该缓冲区中的字节)在缓冲区数组中的偏移量;必须为非负数并且不能大于 srcs.length

       length

- 要访问的最大缓冲区数;必须为非负数并且不能大于 srcs.length - offset

返回:写入的字节数,可能为零

抛出:

NotYetConnectedException

- 如果尚未连接此通道

ClosedChannelException

- 如果此通道已关闭

      AsynchronousCloseException

- 如果正在进行写入操作时另一个线程关闭了此通道

      ClosedByInterruptException

- 如果正在进行写入操作时另一个线程中断了当前线程,因此关闭了该通道并将当前线程的状态设置为中断

      IOException

- 如果发生其他 I/O 错误

14.public final long write(ByteBuffer[] srcs)throws IOException  将字节序列从给定的缓冲区写入此通道。

调用此方法的形式为 c.write(srcs) ,该调用与以下调用完全相同:  c.write(srcs, 0, srcs.length);

指定者:接口

GatheringByteChannel

中的

write

返回: 写入的字节数,可能为零

抛出:

NotYetConnectedException

- 如果尚未连接此通道

ClosedChannelException

- 如果此通道已关闭

AsynchronousCloseException

- 如果正在进行写入操作时另一个线程关闭了此通道

ClosedByInterruptException

- 如果正在进行写入操作时另一个线程中断了当前线程,因此关闭了该通道并将当前线程的状态设置为中断

I

OException

- 如果发生其他 I/O 错误