JavaNIO之Channel
JavaNIO中的Channel类似Stream,可以读写,通常与Buffer进行交互,不存储数据,只负责在具体的io设备与buffer之间搬运数据。
概述
分类
Java NIO中Channel的实现类,分为:
- FileChannel,连接一个文件的通道,对文件进行读,写,映射到直接内存操作;
- DatagramChannel,通过 UDP 读写网络中的数据通道;
- SocketChannel,通过 TCP 读写网络中的数据通道;
- ServerSocketChannel,可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。
Channel和Buffer的交互关系
注: 这里所说的I/O设备为文件、套接字等。
从I/O设备中读数据:
- 创建对应的通道,如FileChannel创建一个文件读写的通道;
- 调用通道的
read(buffer)
方法,通道会向Buffer中填充I/O设备中的数据; - 填充完成后,应用程序从buffer中读取数据。
向I/O设备中写数据:
- 创建对应的通道和缓存;
- 应用程序将要写的数据,先put进buffer中;
- 调用通道的
write()
方法,通道会将数据输出到I/O设备中。
FileChannel
一个简单的例子:
1 | private static void fileChannelDemo() { |
结果:打印出文件中的内容,并在文件的最后添加了完成。
ServerSocketChannel
ServerSocketChannel 负责监听连接,服务端使用,在监听到 TCP 连接时会产生一个 SocketChannel 实例与客户端进行连接和数据交互。一般为了支持并发,服务端在产生 SocketChannel 之后可以通道实例放到一个队列中,用一个线程池去处理队列中的通道。
使用步骤:
打开一个ServerSocketChannel通道,并绑定端口号:
1 | ServerSocketChannel ssc = ServerSocketChannel.open(); |
阻塞接收连接:
1 | // 循环等待连接的到来 |
处理SocketChannel
,读取,与buffer的交互:
1 | // 读客户端的数据 |
关闭资源:
1 | client.close(); |
SocketChannel
SocketChannel 负责 TCP 套接字的连接和数据传输,客户端和服务端都需要用到。SocketChannel 是线程安全的,支持多线程访问。
SocketChannel 有阻塞连接和非阻塞连接两种模式。对于阻塞连接,读取数据时会阻塞,直到有数据过来或者连接被关闭;对于非阻塞连接,调用 read() 方法时无论是否有数据都会立即返回。可以调用 configureBlocking(boolean block) 来配置为阻塞通道或非阻塞通道。
使用步骤:
打开并连接服务端的套接字:
1 | SocketChannel socketChannel = |
配置通道的阻塞还是非阻塞的方式:
1 | // 配置是否阻塞,阻塞在读取数据的时候,没有数据是否阻塞等待 |
通道和buffer的读写:
1 | ByteBuffer buffer = ByteBuffer.allocate(256); |
DatagramChannel
数据报通道 DatagramChannel 表示 UDP 通道。UDP 是无连接协议,在收发数据时不需要进行连接。与 FileChannel 和 SocketChannel 使用 read()/write() 不同,DatagramChannel 通常使用 receive()/send() 来收发数据。receive() 在接收数据之后会返回发送方的地址,send() 方法在发送数据的时候需要指定接收方的地址。
DatagramChannel 支持阻塞模式和非阻塞模式。非阻塞模式时,receive(ByteBuffer dst) 方法会立即返回,如果有数据,则会返回发送方的地址;如果没有数据,则返回 null。类似地,非阻塞模式下 send(ByteBuffer src, SocketAddress) 也会立即返回,返回的结果为发送的字节数。
服务端使用步骤:
打开通道并且绑定端口:
1 | DatagramChannel dc = DatagramChannel.open(); |
数据交互:
使用receive 和 send方法,
1 | SocketAddress address = channel.receive(buf); |
关闭通道
1 | channel.close(); |
客户端使用步骤:
不需要绑定端口,但是要指定服务端的地址:
1 | // 定义服务端的地址 |
调用send的时候传这个地址。