马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
Java编程中BIO、NIO、AIO是三种差异的I/O(输入/输出)模子,它们代表了差异的I/O处置惩罚方式。
Netty就是基于Java的NIO(New Input/Output)类库编写的一个高性能、异步变乱驱动的网络应用步调框架,用于快速开发可维护的高性能协议服务器和客户端。
先来相识一下根本的三种根本的io模子:
BIO(Blocking I/O,壅闭I/O)
界说:BIO是Java最传统的I/O模子,基于流的同步壅闭I/O操纵。每个毗连都会占用一个线程,当举行I/O操纵时,线程会被壅闭,直到操纵完成。
特点:
同步壅闭:每个I/O操纵都会壅闭当火线程,直到操纵完成。
线程占用:每个毗连必要一个独立的线程,线程资源斲丧较大。
实现简单:代码实现相对简单,易于明确和编写。
作用:实用于毗连数较少且固定的架构,如传统的C/S架构。由于着实现简单、编程直观,因此在一些简单的网络编程场景中仍然被使用。
创建客户端和服务端演示数据吸收与传输。- //服务端
- public static void main(String[] args) {
- try (ServerSocket serverSocket = new ServerSocket(9999)) {
- while (true) {
- Socket socket = serverSocket.accept(); // 持续监听新连接
- new Thread(() -> { // 为每个客户端创建独立线程
- try (BufferedReader reader = new BufferedReader(
- new InputStreamReader(socket.getInputStream()))) {
- String line;
- while ((line = reader.readLine()) != null) {
- System.out.println("客户端[" + socket.getPort() + "] 消息: " + line);
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }).start();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- //客户端
- public static void main(String[] args) {
- System.out.println("客户端启动...");
- try {
- //创建套接字
- Socket socket = new Socket("127.0.0.1", 9999);
- //获取输出流发送消息
- PrintStream ps = new PrintStream(socket.getOutputStream());
- Scanner sc = new Scanner(System.in);
- while (true){
- System.out.println("请输入信息:");
- ps.println(sc.nextLine());
- ps.flush();
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
复制代码 NIO(Non-blocking I/O,非壅闭I/O)
界说:NIO是Java 1.4引入的新I/O API,基于通道(Channel)和缓冲区(Buffer)的非壅闭I/O操纵。
特点:
非壅闭:I/O操纵不会壅闭线程,线程可以在期待数据时实行其他使命。
多路复用:通过Selector可以管理多个Channel,进步了资源使用率。
高性能:实用于高并发场景,镌汰线程开销和上下文切换。
焦点组件:
缓冲区(Buffer):用于存储数据的固定巨细的内存地域,提供了多种范例的缓冲区,如ByteBuffer、CharBuffer等。
通道(Channel):用于数据读写的通道,支持非壅闭模式,与缓冲区共同使用。
选择器(Selector):允许单个线程同时处置惩罚多个通道的I/O变乱。
作用:实用于毗连数较多且毗连较短的架构,如高并发的服务器端应用。NIO提供了更高效、更机动的I/O操纵方式,明显进步了体系的并发性能和吞吐量。- //服务端
- public static void main(String[] args) throws Exception {
- //创建连接通道,ServerSocketChannel 绑定端口,监听新的客户端连接请求。它本身不处理任何数据传输。
- ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
- // 设置通道为非阻塞模式
- serverSocketChannel.configureBlocking(false);
- //绑定端口
- serverSocketChannel.bind(new InetSocketAddress(9999));
- //创建 Selector 并注册 ACCEPT 事件
- Selector selector = Selector.open();
- serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
- System.out.println("NIO 服务端启动...");
- //阻塞等待事件发生
- while (selector.select()>0){
- //获取到所有事件
- Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
- //遍历所有事件
- while (iterator.hasNext()){
- SelectionKey key = iterator.next();
- //检查是否有新的连接请求
- if(key.isAcceptable()){
- //为每一个创建新的通道
- SocketChannel clientChannel = serverSocketChannel.accept();
- clientChannel.configureBlocking(false);
- clientChannel.register(selector,SelectionKey.OP_READ);
- }else if(key.isReadable()){
- //处理读数据
- SocketChannel channel = (SocketChannel)key.channel();
- ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
- int bytesRead = 0;
- while ((bytesRead = channel.read(byteBuffer)) > 0){
- byteBuffer.flip();
- String message = new String(byteBuffer.array(),0,bytesRead);
- System.out.println("接收客户端信息:"+message);
- byteBuffer.clear();
- //回写数据给客户端
- ByteBuffer response = ByteBuffer.wrap(("ECHO: " + message).getBytes());
- channel.write(response);
- }
- }
- iterator.remove();
- }
- }
- }
- //客户端
- public static void main(String[] args) throws Exception {
- // 1. 创建 SocketChannel 并连接服务器
- SocketChannel socketChannel = SocketChannel.open();
- socketChannel.connect(new InetSocketAddress("127.0.0.1", 9999));
- socketChannel.configureBlocking(false); // 非阻塞模式
- System.out.println("NIO 客户端已连接");
- //接收线程
- new Thread(() -> {
- ByteBuffer buffer = ByteBuffer.allocate(1024);
- while (true) {
- try {
- int bytesRead = socketChannel.read(buffer);
- if (bytesRead > 0) {
- buffer.flip();
- byte[] data = new byte[buffer.remaining()];
- buffer.get(data);
- System.out.println("收到服务端响应: " + new String(data));
- buffer.clear();
- }
- } catch (IOException e) {
- System.out.println("连接已断开");
- break;
- }
- }
- }).start();
- //发送消息
- ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
- Scanner sc = new Scanner(System.in);
- while (true){
- System.out.println("请输入信息:");
- String msg = sc.nextLine();
- byteBuffer.put(("AA:"+msg).getBytes(StandardCharsets.UTF_8));
- byteBuffer.flip();
- socketChannel.write(byteBuffer);
- byteBuffer.clear();
- }
- }
复制代码 AIO(Asynchronous I/O,异步I/O)
界说:AIO是Java 7引入的异步I/O API,基于异步通道(AsynchronousChannel)和异步回调机制。
特点:
异步非壅闭:I/O操纵是异步的,通过回调处置惩罚结果,不壅闭线程。
回调机制:通过回调函数处置惩罚I/O操纵结果,进步了步调的机动性。
高性能:实用于高并发、高吞吐量的场景。
工作方式:
步调发起一个异步I/O哀求,并提供一个回调函数。
步调无需期待I/O操纵完成,而是立刻返回,继续实行其他使命。
当I/O操纵完成后,体系会调用之条件供的回调函数,转达结果或状态信息。
作用:实用于毗连数较多且毗连时间较长的架构,如高并发的服务器端应用。AIO提供了真正的异步I/O操纵方式,进一步进步了体系的并发性能和吞吐量。
Netty
先相识一下netty出现的缘故原由,是干嘛用的?
Java NIO的复杂性:
Java NIO固然提供了非壅闭IO的本领,但其API设盘算为底层,使用起来比力复杂。开发者必要处置惩罚大量的细节,如选择器的管理、缓冲区的操纵等,这增长了开发的难度和堕落的风险。
性能瓶颈:
在高并发场景下,直接使用Java NIO举行网络编程大概会碰到性能瓶颈。比方,选择器的实现和多线程管理的复杂性大概导致性能降落。
缺乏高级功能:
Java NIO仅提供了根本的非壅闭IO机制,缺乏一些高级功能,如协议编解码、连继承理等。这些功能在开发网络应用时非常紧张,但实现起来却相对复杂。
简化网络编程:
Netty封装了Java NIO的复杂性,提供了一套简便易用的API。开发者可以使用这些API快速构建网络应用,而无需关注底层的细节。
进步性能:
Netty采取了异步非壅闭IO模子,并支持零拷贝等技能,可以在包管高性能的同时,镌汰CPU和内存资源的斲丧。这使得Netty在高并发场景下表现尤为精彩。
支持多种协议:
Netty内置了对多种协议的支持,如TCP、UDP、HTTP、WebSocket等。开发者可以轻松地使用这些协议构建网络应用,而无需自己实现协议编解码等复杂功能。
机动的扩展性:
Netty提供了丰富的扩展点,如ChannelHandler、Codec等。开发者可以通过实现这些接口来扩展Netty的功能,以满足特定的业务需求。
广泛的应用场景:
Netty颠末广泛的使用和验证,具有高稳固性和可靠性,实用于各种网络应用场景,如分布式体系、微服务架构中的通讯组件、及时通讯体系、游戏服务器等。
它提供了丰富的错误处置惩罚和规复机制,可以大概有用地处置惩罚网络通讯中的各种非常环境。
netty焦点上风:
异步变乱驱动、零拷贝、内存池、高度可定制。
先大概相识一下 Reactor 模子(单线程、多线程、主从多线程)。
由于Reactor 模式是 Netty 高性能和高并发本领的焦点计划根本。Netty 的线程模子、变乱驱动机制和异步非壅闭 I/O 都深度依靠 Reactor 模式。
Reactor 模式是一种 变乱驱动的计划模式,用于处置惩罚高并发的 I/O 哀求。其焦点头脑是 用一个或多个线程监听变乱(如毗连、读写哀求),并将变乱分发给对应的处置惩罚器异步处置惩罚,制止线程壅闭和资源浪费。
Reactor模子的焦点组件
变乱源(Event Source):指任何可以产生I/O变乱的对象,比方网络毗连、文件、装备等。
变乱循环(Event Loop):Reactor模子的焦点,负责监控 全部变乱源的状态,并在有变乱发生时将其分发给相应的处置惩罚步调(即回调函数)。
变乱处置惩罚器(Event Handler):处置惩罚特定变乱的代码模块,通常实现为回调函数或方法。针对特定的变乱源,每一个变乱源通常都有一个相应的处置惩罚器,用于处置惩罚该变乱源的I/O变乱。
多路复用器(Demultiplexer):用于监督多个变乱源并将发生的变乱关照给Reactor。常见的实现包罗Java的Selector、Linux的epoll等。
Reactor模子的实现方式
单Reactor单线程模子:全部操纵(毗连、读写)由一个线程完成。计划简单,但在高并发场景下轻易成为性能瓶颈。
单Reactor多线程模子:Reactor线程负责监听和分发变乱,而变乱的处置惩罚则交给线程池中的工作线程完成。这种方式可以大概充实使用多核CPU的处置惩罚本领,但在高并发场景下,Reactor线程大概成为性能瓶颈。
主从Reactor多线程模子(Netty 默认模子-高并发):也称为多Reactor多线程模子。主Reactor线程负责监听和分发毗连变乱,当有新的毗连到来时,将其分发给从Reactor线程处置惩罚。从Reactor线程负责监听和分发读写变乱,并交给线程池中的工作线程处置惩罚。这种方式可以大概进一步进步体系的并发处置惩罚本领和可扩展性。
写个netty服务端示例看一下:- // 1. 创建主 Reactor(处理连接)管理一组 EventLoop,每个线程绑定一个 EventLoop(事件循环线程)
- EventLoopGroup bossGroup = new NioEventLoopGroup(1); // 主线程组(通常 1 个线程)
- // 2. 创建子 Reactor(处理 I/O)
- EventLoopGroup workerGroup = new NioEventLoopGroup(); // 子线程组(默认 CPU 核数 × 2)
- //Reactor 模式配置入口 绑定主/子线程组、设置 Channel 类型
- ServerBootstrap server = new ServerBootstrap();
- server.group(bossGroup, workerGroup) // 绑定主从线程组
- .channel(NioServerSocketChannel.class) // 设置 Channel 类型(NIO)代表一个 Socket 连接或监听端口
- .childHandler(new ChannelInitializer<SocketChannel>() {
- @Override
- protected void initChannel(SocketChannel ch) {
- ch.pipeline().addLast(new ServerHandler()); // 添加业务处理器,这里需要自己实现
- }
- });
- // 3. 绑定端口并启动服务
- ChannelFuture future = server.bind(8080).sync();
- //等待服务器通道关闭
- future.channel().closeFuture().sync();
- //关闭通道
- finally {
- workerGroup.shutdownGracefully();
- bossGroup.shutdownGracefully();
- }
- //业务处理器
- public class ServerHandler extends ChannelInboundHandlerAdapter {
- @Override
- public void channelActive(ChannelHandlerContext ctx) throws Exception {
- System.out.println("客户端连接成功...");
- }
- }
复制代码 Channel:
在Netty中,Channel是一个焦点概念,Channel提供了数据的读取和写入操纵,以及与长途端点举行通讯的本领。
通过Channel可以获取到许多信息,比如:本地所在、长途所在、Channel的EventLoop、Channel的Pipeline等。
Channel 生命周期:
channelRegistered (初始化操纵)→ channelActive (毗连)→ channelRead(数据吸收) → channelInactive(断开)→ channelUnregistered(注销)
Selector:
Selector是Java NIO(New Input/Output)中的一个焦点组件,用于监控 多个Channel(通道)的状态,比方毗连、读、写等变乱。在netty中Selector被封装在NioEventLoop中,当Channel注册到Selector并指定感爱好的变乱范例(如毗连、读、写等)后,会返回一个SelectionKey,用于表现Selector与Channel之间的关联关系。Selector会不绝地轮询其注册的Channel,假如有变乱发生,Selector会将相应的SelectionKey放入停当变乱聚集中。变乱循环线程会从停当变乱聚集中取出SelectionKey,并根据变乱范例调用相应的ChannelHandler举行处置惩罚。处置惩罚完成后,变乱循环线程会将Channel放回到Selector中,继续期待下一次变乱的发生。
EventLoopGroup:
管理一组 EventLoop,通常分为 bossGroup(处置惩罚毗连)和 workerGroup(处置惩罚 I/O)。
设置线程数:new NioEventLoopGroup(4) 表现 4 个线程。
ServerBootstrap:
用于启动服务器端的引导类,设置服务器参数和处置惩罚器链设置、启动服务器、关闭服务器。
线程模子:ServerBootstrap允许您设置两个紧张的线程组:bossGroup和workerGroup。
bossGroup用于处置惩罚客户端的毗连哀求,而workerGroup用于处置惩罚已毗连的客户端的I/O操纵。
通道范例:通过channel方法,您可以指定服务器使用的通道范例。对于NIO传输,通常使用NioServerSocketChannel。
通道选项:使用option方法可以设置服务器通道的选项,如SO_BACKLOG(TCP毗连哀求的最大队列长度)和SO_REUSEADDR(允许所在重用)。
子通道选项:childOption方法用于设置已毗连客户端的通道选项,如SO_KEEPALIVE(保持毗连活动状态)。
Option:可以应用于Channel或Bootstrap上。
ChannelOption:专门用于设置Channel的参数。
父处置惩罚器:通过handler方法,您可以设置处置惩罚服务器通道I/O变乱的处置惩罚器。这通常用于处置惩罚毗连哀求。
子处置惩罚器:childHandler方法用于设置处置惩罚已毗连客户端I/O变乱的处置惩罚器。这是开发者编写业务逻辑处置惩罚代码的地方,通常通过添加一系列的ChannelHandler来实现。
ChannelHandler
ChannelHandler是ChannelPipeline中的根本处置惩罚单位,负责处置惩罚或拦截入站和出站变乱。每个ChannelHandler都有一个关联的ChannelHandlerContext,通过它可以方便地与其他组件举行交互。ChannelPipeline则是ChannelHandler的容器,负责ChannelHandler的管理和变乱拦截。
pipeline、ChannelPipeline
Pipeline是ChannelPipeline的简称。ChannelPipeline用于处置惩罚网络变乱和数据的活动。负责将一系列的处置惩罚逻辑(称为ChannelHandler)串联起来,形成一个处置惩罚链,对网络变乱举行拦截和处置惩罚。
变乱处置惩罚:ChannelPipeline负责处置惩罚入站(Inbound)和出站(Outbound)变乱,如数据读取、数据写入、毗连创建、毗连断开等。
拦截器链:ChannelPipeline内部维护了一个拦截器链(或称为处置惩罚器链),每个拦截器(即ChannelHandler)都可以对变乱举行处置惩罚或拦截。
动态性:ChannelPipeline允许在运行时动态地添加、删除或更换拦截器,从而机动地扩展和定制网络处置惩罚逻辑。
- 启动服务器:
设置完成后,通过调用bind方法并传入服务器的端标语,ServerBootstrap将启动服务器并绑定到指定的端口。
bind方法返回一个ChannelFuture对象,您可以使用sync方法期待服务器启动完成。
ChannelFuture是Netty框架中特有的接口,继续自Java的Future接口。在Netty中,全部的I/O操纵都是异步的,ChannelFuture用于在操纵完成时关照应用步调,以便应用步调可以实行某些操纵或检索操纵的结果。
- 关闭:
当服务器必要关闭时,可以调用ChannelFuture对象的channel().closeFuture().sync()方法,期待服务器通道关闭。
末了,调用bossGroup和workerGroup的shutdownGracefully方法,以优雅地断开毗连并关闭线程组。
ChannelHandlerContext:
ChannelHandlerContext封装了Channel和ChannelPipeline,使得ChannelHandler可以方便地访问和操纵ChannelPipeline和Channel。
ChannelHandlerContext提供了许多方法,用于操纵和流传变乱,如写入数据、革新数据、触发读变乱等。
ChannelHandlerContext允许ChannelHandler将变乱转达给ChannelPipeline中的下一个处置惩罚器。比方,当一个入站变乱(如数据读取)发生时,ChannelHandlerContext可以调用fireChannelRead方法,将变乱转达给下一个入站处置惩罚器。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|