Java NIO(Non-blocking I/O,非阻塞 I/O)是 Java 平台中用于处理大量并发连接的一种高效 I/O 模型。NIO 的引入极大地提高了 Java 应用程序在网络通信方面的性能。Netty 是一个基于 NIO 的高性能网络框架,它利用 Java NIO 的特性来构建可扩展的服务器和客户端应用。本文将以技术综述的形式,介绍 Java NIO 的基本概念,并通过示例代码展示如何使用 Java NIO 和 Netty 来开发网络应用。
Java NIO 基础
Java NIO 引入了几个核心组件:Buffer、Channel、Selector 和 SocketChannel。
- Buffer:用于存储数据。Buffer 是一个容器,用于存放从 Channel 读取的数据或写入 Channel 的数据。
- Channel:用于读写数据。Channel 是双向的,可以读也可以写。
- Selector:用于监听多个 Channel 的 I/O 状态。Selector 可以监听 Channel 是否准备好读、写或连接等操作。
- SocketChannel:用于网络通信。它是 Channel 的一个子类,专门用于处理 TCP/IP 连接。
Java NIO 示例代码
下面是一个简单的 Java NIO 服务器端和客户端的示例代码,用于演示如何使用 Java NIO 进行网络通信。
服务器端代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class NioServer {
private static final int PORT = 8080;
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().bind(new InetSocketAddress(PORT));
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
if (key.isAcceptable()) {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
}
if (key.isReadable()) {
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int read = sc.read(buffer);
if (read > 0) {
buffer.flip();
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
System.out.println("Received from client: " + new String(data));
}
}
iterator.remove();
}
}
}
}
客户端代码
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class NioClient {
private static final int PORT = 8080;
private static final String HOST = "localhost";
public static void main(String[] args) throws IOException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new java.net.InetSocketAddress(HOST, PORT));
while (!socketChannel.finishConnect()) {
// 等待连接完成
}
ByteBuffer buffer = ByteBuffer.wrap("Hello, Server!".getBytes());
socketChannel.write(buffer);
socketChannel.close();
}
}
Netty 示例代码
Netty 是一个基于 NIO 的高性能网络框架,它简化了 Java NIO 的使用。下面是使用 Netty 构建一个简单的 TCP 服务器和客户端的示例。
服务器端代码
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class NettyServer {
private static final int PORT = 8080;
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new StringEncoder());
ch.pipeline().addLast(new NettyServerHandler());
}
});
ChannelFuture f = b.bind(PORT).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("Received from client: " + msg);
ctx.writeAndFlush(Unpooled.copiedBuffer("Echo: " + msg.toString(), Unpooled.copiedBuffer(msg.toString(), Unpooled.UTF_8)));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
客户端代码
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class NettyClient {
private static final int PORT = 8080;
private static final String HOST = "localhost";
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new StringEncoder());
ch.pipeline().addLast(new NettyClientHandler());
}
});
ChannelFuture f = b.connect(HOST, PORT).sync();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, Server!", Unpooled.UTF_8));
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("Received from server: " + msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
总结
通过上述技术综述,我们可以了解到 Java NIO 提供了一种非阻塞式的 I/O 模型,使得 Java 应用程序能够处理大量的并发连接。无论是使用原生的 Java NIO 还是基于 NIO 的框架如 Netty,都需要对 Buffer、Channel、Selector 等核心概念有一定的了解。无论是在日常开发还是面试准备中,熟悉这些知识都是非常重要的。