Channel (通道) 介绍
- 通常来说 NIO 中的所有 IO 都是从 Channel 开始的
- 从通道进行数据读取: 创建一个缓冲区, 然后请求通道读取数据
- 从通道进行数据写入: 创建一个缓冲区, 写入数据, 并要求通道写入数据
Channel 和 Stream 的区别
- Channel 可以读也可以写; Stream 一般是单向的, 只能读或写(所以之前用 Stream 进行 IO 操作的时候需要分别创建一个输入流和一个输出流)
- Channel 可以异步读写
- Channel 总是基于 Buffer (缓冲区)来读写
Channel 的几个重要实现
- FileChannel : 用于文件的数据读写
- DatagramChannel : 用于 UDP 的数据读写
- SocketChannel : 用于 TCP 的数据读写, 一般是客户端实现
- ServerSocketChannel : 允许监听 TCP 连接请求, 每个请求会创建一个 SocketChannel, 一般是服务端实现
FileChannel 的使用
public static void main(String[] args) throws IOException {
ByteBuffer buffer1 = ByteBuffer.allocate(100);
FileChannel inChannel = new FileInputStream("data.txt").getChannel();
inChannel.read(buffer1);
inChannel.close();
buffer1.flip();
System.out.println("\n--------------------读 Buffer-----------------------");
while (buffer1.hasRemaining()) {
System.out.print((char) buffer1.get());
}
buffer1.clear();
buffer1.put("woxihuannijinfaxiaojiejiewohaoxihuanni".getBytes());
FileChannel outChannel = new FileOutputStream("data.txt",true).getChannel();
buffer1.flip();
outChannel.write(buffer1);
outChannel.close();
}
- 开启 FileChannel
- 需要通过 InputStream, OutputStream 或 RandomAccessFile 获取 FileChannel
- 从 FileChannel 读取数据 / 向 FileChannel 写入数据
- 关闭 FileChannel
SocketChannel 和 ServerSocketChannel 的使用
- SocketChannel 创建基于 tcp 协议的客户端对象, 因为 SocketChannel 中不存在 accept() 方法, 所以它不能成为一个服务端程序
- SocketChannel 对象通过 connect() 方法可以连接到其他 tcp 服务器程序
public class WebClient {
public static void main(String[] args) throws IOException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1",19999));
final ByteBuffer writeBuffer = ByteBuffer.allocate(128);
writeBuffer.put("hello, i am client".getBytes());
writeBuffer.flip();
socketChannel.write(writeBuffer);
final ByteBuffer readBuffer = ByteBuffer.allocate(128);
socketChannel.read(readBuffer);
readBuffer.flip();
while (readBuffer.hasRemaining()){
System.out.print((char)readBuffer.get());
}
socketChannel.close();
}
}
- ServerSocketChannel 允许监听 tcp 连接请求
- 通过 ServerSocketChannelImpl 的 accept() 方法, 可以创建一个 SocketChannel 对象, 从客户端读/写数据
public class WebServer {
public static void main(String[] args) throws IOException {
final ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress("127.0.0.1", 19999));
final SocketChannel socketChannel = serverSocketChannel.accept();
final ByteBuffer writeBuffer = ByteBuffer.allocate(128);
writeBuffer.put("hello, i am server".getBytes()).flip();
socketChannel.write(writeBuffer);
final ByteBuffer readBuffer = ByteBuffer.allocate(128);
socketChannel.read(readBuffer);
readBuffer.flip();
while (readBuffer.hasRemaining()) {
System.out.print((char) readBuffer.get());
}
socketChannel.close();
serverSocketChannel.close();
}
}
客户端
- 通过SocketChannel连接到远程服务器
- 创建读数据/写数据缓冲区对象来读取服务端数据或向服务端发送数据
- 关闭SocketChannel
服务端
- 通过ServerSocketChannel 绑定ip地址和端口号
- 通过ServerSocketChannelImpl的accept()方法创建一个SocketChannel对象用户从客户端读/写数据
- 创建读数据/写数据缓冲区对象来读取客户端数据或向客户端发送数据
- 关闭SocketChannel和ServerSocketChannel
|