BIO,NIO,AIO

news2024/11/27 20:28:53

IO模型

用什么样的通道进行数据传输和接收,java支持3种io网络编程模式 BIO NIO AIO

BIO

同步阻塞 一个客户端连接对应一个处理线程

在这里插入图片描述
BIO示例代码(客户端和服务端)

package com.tuling.bio;

import java.io.IOException;
import java.net.Socket;

public class SocketClient {

    public static void main(String[] args) throws IOException, InterruptedException {
        Socket socket = new Socket("127.0.0.1", 9000);
        //向服务端发送数据
        socket.getOutputStream().write("HelloServer".getBytes());
        socket.getOutputStream().flush();
        System.out.println("向服务端发送数据结束");
        byte[] bytes = new byte[1024];
        //接收服务端回传的数据
        socket.getInputStream().read(bytes);
        System.out.println("接收到服务端的数据:" + new String(bytes));
        socket.close();
    }
}
package com.tuling.bio;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9000);
        while (true) {
            System.out.println("等待连接。。");
            //阻塞方法
            Socket clientSocket = serverSocket.accept();
            System.out.println("有客户端连接了。。");
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        handler(clientSocket);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }

    private static void handler(Socket clientSocket) throws IOException {
        byte[] bytes = new byte[1024];
        System.out.println("准备read。。");
        //接收客户端的数据,阻塞方法,没有数据可读时就阻塞
        int read = clientSocket.getInputStream().read(bytes);
        System.out.println("read完毕。。");
        if (read != -1) {
            System.out.println("接收到客户端的数据:" + new String(bytes, 0, read));
        }
        clientSocket.getOutputStream().write("HelloClient".getBytes());
        clientSocket.getOutputStream().flush();
    }
}

先启动服务端,再启动客户端,客户端和服务端直接可以互发消息
缺点:io代码里read操作是阻塞操作,如果连接不做数据读写操作会导致线程阻塞,浪费资源
如果线程很多,会导致服务器线程太多,压力太大
应用场景:连接数目小且固定的架构,对服务器资源要求比较高

NIO

同步非阻塞 一个线程可以处理多个请求。 客户端发送的请求可以注册到多路复用selector上,多路复用查询到IO请求就进行处理

应用场景 连接多且连接比较短的架构,如聊天服务器,编程比较复杂

nio示例代码

package com.tuling.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class NioServer {

    // 保存客户端连接
    static List<SocketChannel> channelList = new ArrayList<>();

    public static void main(String[] args) throws IOException {

        // 创建NIO ServerSocketChannel,与BIO的serverSocket类似
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.socket().bind(new InetSocketAddress(9000));
        // 设置ServerSocketChannel为非阻塞
        serverSocket.configureBlocking(false);
        System.out.println("服务启动成功");

        while (true) {
            // 非阻塞模式accept方法不会阻塞,否则会阻塞
            // NIO的非阻塞是由操作系统内部实现的,底层调用了linux内核的accept函数
            SocketChannel socketChannel = serverSocket.accept();
            if (socketChannel != null) { // 如果有客户端进行连接
                System.out.println("连接成功");
                // 设置SocketChannel为非阻塞
                socketChannel.configureBlocking(false);
                // 保存客户端连接在List中
                channelList.add(socketChannel);
            }
            // 遍历连接进行数据读取
            Iterator<SocketChannel> iterator = channelList.iterator();
            while (iterator.hasNext()) {
                SocketChannel sc = iterator.next();
                ByteBuffer byteBuffer = ByteBuffer.allocate(128);
                // 非阻塞模式read方法不会阻塞,否则会阻塞
                int len = sc.read(byteBuffer);
                // 如果有数据,把数据打印出来
                if (len > 0) {
                    System.out.println("接收到消息:" + new String(byteBuffer.array()));
                } else if (len == -1) { // 如果客户端断开,把socket从集合中去掉
                    iterator.remove();
                    System.out.println("客户端断开连接");
                }
            }
        }
    }
}

nio引入多路复用器示例代码

package com.tuling.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 NioSelectorServer {

    public static void main(String[] args) throws IOException {

        // 创建NIO ServerSocketChannel
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.socket().bind(new InetSocketAddress(9000));
        // 设置ServerSocketChannel为非阻塞
        serverSocket.configureBlocking(false);
        // 打开Selector处理Channel,即创建epoll
        Selector selector = Selector.open();
        // 把ServerSocketChannel注册到selector上,并且selector对客户端accept连接操作感兴趣
        SelectionKey selectionKey = serverSocket.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务启动成功");

        while (true) {
            // 阻塞等待需要处理的事件发生
            selector.select();

            // 获取selector中注册的全部事件的 SelectionKey 实例
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();

            // 遍历SelectionKey对事件进行处理
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                // 如果是OP_ACCEPT事件,则进行连接获取和事件注册
                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = server.accept();
                    socketChannel.configureBlocking(false);
                    // 这里只注册了读事件,如果需要给客户端发送数据可以注册写事件
                    SelectionKey selKey = socketChannel.register(selector, SelectionKey.OP_READ);
                    System.out.println("客户端连接成功");
                } else if (key.isReadable()) {  // 如果是OP_READ事件,则进行读取和打印
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(128);
                    int len = socketChannel.read(byteBuffer);
                    // 如果有数据,把数据打印出来
                    if (len > 0) {
                        System.out.println("接收到消息:" + new String(byteBuffer.array()));
                    } else if (len == -1) { // 如果客户端断开连接,关闭Socket
                        System.out.println("客户端断开连接");
                        socketChannel.close();
                    }
                }
                //从事件集合里删除本次处理的key,防止下次select重复处理
                iterator.remove();
            }
        }
    }
}

NIO三大核心组件: channel buffer selector
channel 通道 ,底层数组
buffer 缓冲
在这里插入图片描述
nio底层在jdk1.4版本基于linux内核函数select()或poll()来实现,类似于nioserver代码,每次都会轮询所有的channel。看哪个有读取事件即进行处理,没有继续遍历。 jdk1.5后引入epoll基于事件相应来优化nio

在这里插入图片描述
AIO 异步非阻塞 一般用于连接数多且连接时间较长的应用 jdk7支持

为什么netty 使用NIO而不是AIO
在linux系统,aio底层仍然使用epoll,没有很好实现AIO,性能没有明显优势,而且被jdk封装不易优化。
netty是异步非阻塞框架,对于aio做了很多异步封装

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/402524.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WIFI P2P架构

WI-FI P2P定义架构3个组件组织结构技术标准P2P DiscoveryDevice Discovery&#xff08;扫描&#xff09;流程p2p probe 管理帧Group Formation&#xff08;组网&#xff09;GO Negotiation&#xff08;GON&#xff09;流程P2P Public Action管理帧Provision Discovery&#xff…

Rust Web 进阶(一):Rust异步编程(Tokio)

这一篇将讲解什么是和为什么进行异步编程&#xff0c;Rust 怎么样进行异步编程以及其机制&#xff0c;并且讲解目前 rust 常用的异步编程的函数库。本章的内容来自杨旭老师的教程&#xff1a; https://www.bilibili.com/video/BV16r4y187P4/?spm_id_from333.999.0.0&vd_s…

ADSP21489之CCES开发笔记(七)

一、SPORT简介&#xff1a;ADI21489具有八个独立的同步串行端口(SPORT)&#xff0c;可为各种外围设备提供I/O接口。他们是称为SPORT0至SPORT7&#xff0c;每个SPORT都有自己的一组控制寄存器和数据缓冲器&#xff0c;具有一定范围的时钟和帧同步选项。 二、特性&#xff1a;支持…

【云原生】Apisix接入Nacos、K8s服务注册中心自动获取服务

背景我在K8s中部署了两个使用SpringCLoudK8s框架的微服务&#xff0c;每个服务既暴露了HTTP接口方便测试&#xff0c;也暴露了gRpc接口更接近生产&#xff0c;他们的端口如下所示&#xff1a;常规功能上游我们可以在这里配置我们的服务HTTP配置一个HTTP服务&#xff0c;输入地址…

设计模式 - 行为型 - 模板模式学习

现象&#xff1a; 设计模式 - 行为型 - 模板模式学习 介绍&#xff1a; 模板模式的设计思路&#xff0c;在抽象类中定义抽象方法的执行顺序&#xff0c; 并将抽象方法设定为只有子类实现&#xff0c;但不提供独立访问的方法 只能通过已经被安排好的定义方法去执行 可以控制整…

如何快速生成数据字典SQL语句

如何快速生成数据字典SQL语句 一、首先我们找到需要生成的数据字典的国家标准 以民族数据字典为例 打开浏览器搜索民族字典代码表得到如下数据&#xff0c;并把得到的数据存入Excel表格中 国标民族数据字典 国标民族字典 第七次全国人口普查民族代码表与民族国标代码 第七次…

JVM垃圾回收之GCRoots可达性分析

已经死亡的对象&#xff0c;不可达的对象&#xff0c;肯定会被回收。 什么样的对象会被回收&#xff1f; 判定的算法有两种&#xff1a;引用计数法和可达性分析算法。 引用计数法&#xff1a;&#xff08;不使用这种&#xff09; 给对象中添加一个引用计数器&#xff0c;每当…

springboot项目打jar包发布上线、查看日志和进程号

目录前言一、Maven打包1.1 删除test文件和对应依赖&#xff08;不建议&#xff09;1.2 pom.xml中配置跳过测试1.3 使用idea打包1.4 使用maven命令打包二、启动jar包2.1 简单启动2.2 后台运行并打印日志2.3 脚本启动三、查看日志3.1 tail命令查看日志3.2 cat命令查看日志四、其他…

员工为什么对绩效考核不满意?管理者应该怎么做?

绩效考核是公司管理员工的重要工具&#xff0c;员工通过绩效考核可以衡量自己的工作效果和完成任务的能力&#xff0c;能够帮助管理者更好的了解员工的工作情况和绩效表现。 但是&#xff0c;现实中很多员工对绩效考核“不满意”&#xff0c;认为绩效考核不公正、不透明、不准确…

docker基础命令-阳哥

docker基础篇-阳哥 文章目录docker基础篇-阳哥centos7最小安装准备工作网络设置安装必备工具1.1 安装工具1.5 优化ssh连接1.1 修改ssh服务的配置文件1.2 找到对应的行数修改如下1.3 修改完成之后重启ssh服务1.6 永久修改主机名sed命令sed命令替换文本_xbd_zc的博客-CSDN博客1.镜…

《2023年化妆品原料成分趋势报告》| 解码化妆品备案数据,洞悉2023年潜力原料成分

回顾2022年&#xff0c;是中国化妆品行业“历史转折年”。备案制度的全面改革&#xff0c;直接改变了产品备案新格局。法律法规对新品备案提出了详实的要求&#xff0c;新品出炉也设置了更高的门槛&#xff0c;所以我们清晰地看到2022年整体的化妆品备案数据大幅度下滑&#xf…

精心梳理的11个在线常用工具,提高开发效率

1、Hutool工具类——Java开发常用工具类 参考文档&#xff1a;https://hutool.cn/docs/index.html#/ 2、在线工具——各种工具整合 我主要用于时间戳转换&#xff0c;进制转换等。 地址&#xff1a;https://tool.lu/ 3、蛙蛙工具——各种文本字符等整合工具 https://www…

python@pyside样式化

文章目录refWidget类创建样式化文件qss引用样式并启动应用ref Styling the Widgets Application - Qt for PythonQt Style Sheets Reference | Qt Widgets 5.15.12 Widget类创建 创建一个简单界面(菜单主要内容)它们是水平布局 主要内容包括一段文本和一个按钮,它们是垂直布…

AI大模型,驶向产业何方?

技术更迭&#xff0c;已不是壁垒&#xff0c;国产式AI需要的是产品的创新思维&#xff0c;以及对需求的产品变现能力。 作者|斗斗 出品|产业家 “AI炒了那么多年&#xff0c;第一次感觉它真的要来了。”国内某论坛中&#xff0c;带有ChatGPT的词条下&#xff0c;几乎都会出…

【Java开发】设计模式 01:单例模式

1 单例模式介绍单例模式&#xff08;Singleton Pattern&#xff09;是Java中最为基础的设计模式。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类&#xff0c;该类负责创建自己的对象&#xff0c;同时确保只有单个对…

打怪升级之使用csv文件发送UDP数据

面临的困难 如果你想做一个基于UDP包的数据处理问题的话&#xff0c;比较好的办法是使用csv文件来进行数据的保存&#xff08;csv文件比较简单&#xff0c;方便进行各种处理&#xff09;。 CSV文件格式简单&#xff0c;一方面它可以直接被excel处理&#xff0c;另一方面它完全…

PDF转word在线转换方法!操作简单又高效

相信很多已经工作的人都知道&#xff0c;PDF文件格式的优点在于兼容性强、安全性高&#xff0c;而且查看和传输给他人都很方便。但是&#xff0c;这种格式的文件也有不太方便的地方&#xff0c;那就是不能对文件内容进行编辑和修改。对于许多人来说&#xff0c;如果想要编辑修改…

接口自动化神器推荐:免费开源Lim接口测试平台

前言 对于传统的实现接口自动化的方案往往是搭建自动化框架&#xff0c;通过excel编写用例来驱动执行&#xff0c;例如常见的万金油技术栈组合&#xff1a;excel&#xff08;编写用例&#xff09;、pytest(用例执行)、allure(测试报告)等。 很多公司往往是通过自动化框架而非…

3-2 SpringCloud快速开发入门:Ribbon 实现客户端负载均衡

接上一章节Ribbon 是什么&#xff0c;这里讲讲Ribbon 实现客户端负载均衡 Ribbon 实现客户端负载均衡 由于 Spring Cloud Ribbon 的封装&#xff0c; 我们在微服务架构中使用客户端负载均衡调用非常简单&#xff0c; 只需要如下两步&#xff1a; 1、启动多个服务提供者实例并…

Matplotlib 绘图实用大全

本文只介绍最简单基本的画图方法 预设 要想画出来的图有些逼格&#xff0c;首先应该进行如下设置 plt.rcParams[font.sans-serif][SimHei] #画图时显示中文字体 plt.rcParams[axes.unicode_minus] False #防止因修改成中文字符&#xff0c;导致某些 unicode 字符不能…