Java的NIO编程-Channel
0x1 主要类型
在Java中有许多NIO Channel
实现,本文只选最主要的四种Channel
:
- FileChannel:文件通道,用于文件的数据读写
- SocketChannel:套接字通道,用于Socket套接字
TCP
连接的数据读写。 - ServerSocketChannel:服务器嵌套字通道(或服务器监听通道),允许我们监听
TCP
连接请求,为每个监听到的请求,创建一个SocketChannel套接字通道。 - DatagramChannel:数据报通道,用于
UDP
协议的数据读写。
0x2 使用
FileChannel
读取通道数据
首先在本地创建文件/home/zheng/channeltest
,在里面编写内容:hello,world!
public class ChannelTest {
public static void main(String[] args) throws IOException {
// 创建输入流
File file = new File("/home/zheng/channeltest");
FileInputStream fis = new FileInputStream(file);
// 获取通道
FileChannel fileChannel = fis.getChannel();
// 创建缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
int length = -1;
// 读取通道数据到缓冲区
while ((length=fileChannel.read(byteBuffer))!=-1){
System.out.println("缓冲区size:"+length);
}
fis.close();
fileChannel.close();
// 读取Buffer缓存数据
byteBuffer.flip();
StringBuilder str = new StringBuilder();
while (byteBuffer.position()!=byteBuffer.limit()){
char c = (char) byteBuffer.get();
str.append(c);
}
System.out.println(str.toString());
}
}
//输出
缓冲区size:13
hello,world!
写入数据到通道
public class ChannelTest {
public static void main(String[] args) throws IOException {
// 创建输入流
File file = new File("/home/zheng/channelOut");
FileOutputStream fos = new FileOutputStream(file);
// 获取通道
FileChannel fileChannel = fos.getChannel();
// 创建缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
byte c = 'c';
byte o = 'o';
byte d = 'd';
byte e = 'e';
byteBuffer.put(c);
byteBuffer.put(o);
byteBuffer.put(d);
byteBuffer.put(e);
int length = 0;
// 缓冲区转换为读模式
byteBuffer.flip();
// 向通道写入数据
while ((length=fileChannel.write(byteBuffer))!=0){
System.out.println("写入数据size:"+length);
}
//强制刷盘
fileChannel.force(true);
fileChannel.close();
}
}
// 输出
写入数据size:4
此时查看文件/home/zheng/channelOut
,里面内容是:code
SocketChannel和ServerSocketChannel
服务端
public class SocketServer { public static void main(String[] args) throws IOException { // 打开ServerSocketChannel ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // 绑定端口 serverSocketChannel.socket().bind(new InetSocketAddress(8989)); // 设置为非阻塞式工作模式(io多路复用) serverSocketChannel.configureBlocking(false); while (true){ // 等待客户端连接 SocketChannel channel = serverSocketChannel.accept(); if (channel!=null){ System.out.println("=================="); System.out.println("客户端地址:"+channel.getRemoteAddress()); ByteBuffer byteBuffer = ByteBuffer.allocate(1024); // 读取通道的数据到缓冲区 channel.read(byteBuffer); // 读取Buffer缓存数据 byteBuffer.flip(); StringBuilder str = new StringBuilder(); while (byteBuffer.position()!=byteBuffer.limit()){ char c = (char) byteBuffer.get(); str.append(c); } System.out.println("接收到消息:"+str.toString()); } } } }
客户端
public class SocketClient { public static void main(String[] args) throws IOException, InterruptedException { // 打开SocketChannel SocketChannel channel = SocketChannel.open(); // 设置为非阻塞式工作模式(io多路复用) channel.configureBlocking(false); // 连接 channel.connect(new InetSocketAddress("127.0.0.1",8989)); while (!channel.finishConnect()){ System.out.println("连接中..."); Thread.sleep(1000); } ByteBuffer byteBuffer = ByteBuffer.allocate(1024); byteBuffer.put((byte)'s'); byteBuffer.flip(); // 从缓冲区写入数据到通道 channel.write(byteBuffer); channel.close(); } }
先运行服务端,然后在运行客户端,此时服务端控制台打印出:
==================
客户端地址:/127.0.0.1:44728
接收到消息:s
DatagramChannel
发送端
public class DatagramClient { public static void main(String[] args) throws IOException { // 开启DatagramChannel DatagramChannel channel = DatagramChannel.open(); // 设置为非阻塞式工作模式(io多路复用) channel.configureBlocking(false); // 创建缓存区 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); Scanner scanner = new Scanner(System.in); System.out.println("请输入要发送的消息:"); while (scanner.hasNext()){ String s = scanner.next(); byteBuffer.put(s.getBytes()); byteBuffer.flip(); // 发送数据 channel.send(byteBuffer,new InetSocketAddress("127.0.0.1",8989)); byteBuffer.clear(); } channel.close(); } }
接收端
public class DatagramServer { public static void main(String[] args) throws IOException { // 开启DatagramChannel DatagramChannel serverChannel = DatagramChannel.open(); // 设置为非阻塞式工作模式(io多路复用) serverChannel.configureBlocking(false); // 绑定监听地址 serverChannel.bind(new InetSocketAddress("127.0.0.1",8989)); // 创建缓存区 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); while (true){ // 接收消息并保存到缓存区 serverChannel.receive(byteBuffer); byteBuffer.flip(); if (byteBuffer.limit()!=0){ // 读取Buffer缓存数据 StringBuilder str = new StringBuilder(); while (byteBuffer.position()!=byteBuffer.limit()){ char c = (char) byteBuffer.get(); str.append(c); } System.out.println("接收到消息:"+str.toString()); byteBuffer.clear(); } byteBuffer.clear(); } } }
源码地址:https://github.com/GreyCode9/nio-demo