下面是“Java NIO通信基础示例详解”的完整攻略。
概述
Java NIO是Java 1.4版本引入的一种新的I/O处理方式。相较于传统的I/O方式,NIO采用了非阻塞式I/O模型,使得I/O的效率更高。本文将详细讲解Java NIO通信的基础知识和实现方式。
NIO简介
NIO是New IO的缩写,它是用来替代传统的Java IO的。Java IO(流和相关类)是面向流的,而NIO是面向缓冲区的。NIO提供了与传统IO不同的优点,例如在面向连接的传输方式中(如TCP),NIO可以通过一个单独的线程处理多个连接的输入和输出数据。
NIO的三个核心组件
1. 缓冲区 Buffer
缓冲区是一个对象,可以在其包含的数组中存储数据。Java NIO中的所有缓冲区都是 Buffer 类的子类。 Buffer 类(如下所示)有以下几个核心属性:
- 容量(Capacity):缓冲区中最多可以存储的数据元素的数量。缓冲区的容量在创建时被固定,并且不能更改。
- 位置(Position):下一个要读取/写入的元素索引。它默认是0,当数据被写入到缓冲区中时,位置向后移动,当从缓冲区中读取数据时,位置向前移动。
- 限制(Limit):可以访问和操作的数据索引的下一个位置索引。默认情况下,限制等于容量。
public abstract class Buffer {
// 容量
private int capacity;
// 下一个要读取/写入的元素索引
private int position = 0;
// 可以访问和操作的数据索引的下一个位置索引
private int limit;
.........
}
2. 通道 Channel
在Java NIO中, Channel是与数据源进行交互的实体。 数据源可以是文件,套接字或服务器端 另一个进程。 Channel的特点是可以被异步地读写。
常用的 Channel 类有:
- FileChannel
- DatagramChannel
- SocketChannel
- ServerSocketChannel
3. 选择器 Selector
Selector是Java NIO中的核心组件之一,用于处理多个 Channel的异步和非阻塞IO操作。可以注册到选择器的每个通道都可以被单个线程处理。因此,一个线程可处理多个输入和输出通道。当一个Channel需要进行读写或者连接时,可以使用选择器进行管理。因为在单个线程中,可以管理多个Channel,因此可以提高系统的运行效率。
NIO通信基础示例
示例1:实现简单的文件读写
首先,我们需要先创建一个Buffer对象将数据写入到文件中,然后读出来。
public void fileChannelDemo() throws IOException {
String content = "hello, Java NIO";
RandomAccessFile file = new RandomAccessFile("test.txt", "rw");
FileChannel channel = file.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 写入Buffer
buffer.put(content.getBytes());
// 缓存区从写模式转为读模式
buffer.flip();
// 将buffer中数据写入到通道
channel.write(buffer);
buffer.clear();
// 将数据从通道读取到buffer中
channel.read(buffer);
buffer.flip();
byte[] result = new byte[buffer.remaining()];
buffer.get(result);
System.out.println(new String(result));
file.close();
}
示例2:实现客户端与服务端通信
在这个例子中,我们将实现客户端和服务端通信,客户端将向服务端发送"hello, NIO"字符串,并从服务端接收到"hello, Java NIO"字符串。
服务端部分
public class Server {
public void server() throws IOException {
//创建选择器
Selector selector = Selector.open();
//创建ServerSocketChannel对象
ServerSocketChannel server = ServerSocketChannel.open();
//设置通道为非阻塞状态
server.configureBlocking(false);
//设置监听的地址
server.socket().bind(new InetSocketAddress(9999));
//将通道注册在选择器上,设置监听事件为:连接(accept)
server.register(selector, SelectionKey.OP_ACCEPT);
//循环等待客户端连接
while(true){
if(selector.select(1000) == 0){
continue;
}
//获取选择的键集合
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> keyIter = keys.iterator();
while(keyIter.hasNext()){
SelectionKey key = keyIter.next();
//删除已经处理的键信息
keyIter.remove();
//处理连接事件(当有客户端连接时)
if(key.isAcceptable()){
//获取相应的ServerSocketChannel
ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
//调用accept方法,接收客户端的连接
SocketChannel socket = serverChannel.accept();
//设置非阻塞状态
socket.configureBlocking(false);
//在选择器上注册相应的事件:读(read)
socket.register(selector, SelectionKey.OP_READ);
} else if(key.isReadable()){//处理读事件
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int readBytes = socketChannel.read(buffer);
if(readBytes > 0){
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
String body = new String(bytes, "UTF-8");
System.out.println("Server: Receive Message -> "+ body);
String response = "hello, Java NIO";
ByteBuffer outBuffer = ByteBuffer.wrap(response.getBytes());
socketChannel.write(outBuffer);//将消息回送给客户端
}
}
}
}
}
}
客户端部分
public class Client {
public void client() throws IOException {
//创建SocketChannel对象
SocketChannel socketChannel = SocketChannel.open();
//设置通道为非阻塞状态
socketChannel.configureBlocking(false);
//连接服务端
socketChannel.connect(new InetSocketAddress("127.0.0.1", 9999));
Selector selector = Selector.open();
//将通道注册在选择器上,设置监听事件为:连接(connect)
socketChannel.register(selector, SelectionKey.OP_CONNECT);
while(true){
if(selector.select(1000) == 0){
continue;
}
//获取选择的键集合
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> keyIter = keys.iterator();
while(keyIter.hasNext()){
SelectionKey key = keyIter.next();
//删除已经处理的键信息
keyIter.remove();
//连接事件(由于客户端是由连接服务器开始的,因此处理连接事件在这个例子中可有可无)
if(key.isConnectable()){
SocketChannel channel = (SocketChannel) key.channel();
//判断是否连接成功
if(channel.finishConnect()){
System.out.println("Client: Connect to server successful!");
ByteBuffer buffer = ByteBuffer.wrap("hello, NIO".getBytes());
buffer.flip();
channel.write(buffer);//向服务器发送消息
} else {
System.exit(1);
}
} else if(key.isReadable()){//处理读事件
SocketChannel socketChannel1 = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int readBytes = socketChannel1.read(buffer);
if(readBytes > 0){
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
String body = new String(bytes, "UTF-8");
System.out.println("Client: Receive Message -> " + body);
}
}
}
}
}
}
上述实例代码实现了Java NIO的基本应用,可以尝试自己写更多的样例来加深理解。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java NIO通信基础示例详解 - Python技术站