Java网络编程-深入理解BIO、NIO

news2024/11/17 17:39:21

深入理解BIO与NIO

BIO

BIO 为 Blocked-IO(阻塞 IO),在 JDK1.4 之前建立网络连接时,只能使用 BIO

使用 BIO 时,服务端会对客户端的每个请求都建立一个线程进行处理,客户端向服务端发送请求后,先咨询服务端是否有线程响应,如果没有就会等待或者被拒绝

BIO 基本使用代码:

服务端:

public class TCPServer {
    public static void main(String[] args) throws Exception {
        // 1.创建ServerSocket对象
        System.out.println("服务端 启动....");
        System.out.println("初始化端口 7777 ");
        ServerSocket ss = new ServerSocket(7777); //端口号
        while (true) {
            // 2.监听客户端
            Socket s = ss.accept(); //阻塞
            // 3.从连接中取出输入流来接收消息
            InputStream is = s.getInputStream(); //阻塞
            byte[] b = new byte[10];
            is.read(b);
            String clientIP = s.getInetAddress().getHostAddress();
            System.out.println(clientIP + "说:" + new String(b).trim());
            // 4.从连接中取出输出流并回话
            OutputStream os = s.getOutputStream();
            os.write("服务端回复".getBytes());
            // 5.关闭
            s.close();
        }
    }
}

客户端:

public class TCPClient {
    public static void main(String[] args) throws Exception {
        while (true) {
            // 1.创建Socket对象
            Socket s = new Socket("127.0.0.1", 7777);
            // 2.从连接中取出输出流并发消息
            OutputStream os = s.getOutputStream();
            System.out.println("请输入:");
            Scanner sc = new Scanner(System.in);
            String msg = sc.nextLine();
            os.write(msg.getBytes());
            // 3.从连接中取出输入流并接收回话
            InputStream is = s.getInputStream(); //阻塞
            byte[] b = new byte[20];
            is.read(b);
            System.out.println("客户端发送消息:" + new String(b).trim());
            // 4.关闭
            s.close();
        }
    }
}

BIO 缺点:

  • Server 端会为客户端的每一个连接请求都创建一个新的线程进行处理,如果客户端连接请求数量太多,则会创建大量线程

NIO

从 JDK1.4 开始,Java 提供了一系列改进的输入/输出的新特性,被统称为 NIO(即 New IO),NIO 弥补了 BIO 的不足,在服务端不需要为客户端大量的请求而建立大量的处理线程,只需要用很少的线程就可以处理很多客户端请求

NIO 和 BIO 有着相同的目的和作用,但是它们的实现方式完全不同;

  • BIO 以流的方式处理数据,而 NIO 以块的方式处理数据,块 IO 的效率比流 IO 高很多。
  • NIO 是非阻塞式的,这一点跟 BIO 也很不相同,使用它可以提供非阻塞式的高伸缩性网络。

NIO 有三大核心部分

  • Channel通道
  • Buffer缓冲区
  • Selector选择器

使用 NIO 时,数据是基于 ChannelBuffer 进行操作的,数据从 Channel 被读取到 Buffer 或者相反,Selector 用于监听多个 Channel 通道的事件(连接事件、读写事件),通过 Selector 就可以实现单个线程来监听多个客户端通道

NIO 中的 Channel 用来建立到目标的一个连接,在 BIO 中流是单向的,例如 FileInputStream 只能进行读取操作,而在 NIO 中 Channel 是双向的,既可以读也可以写

NIO 工作流程图如下:Server 端通过单线程来监听多个客户端 Channel 通道中的事件并进行处理

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

NIO 使用示例

服务端:

public class NIOServer {
    public static void main(String[] args) throws Exception {
        // 1. 开启一个ServerSocketChannel通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 2. 开启一个Selector选择器
        Selector selector = Selector.open();
        // 3. 绑定端口号8888
        System.out.println("服务端 启动....");
        System.out.println("初始化端口 8888 ");
        serverSocketChannel.bind(new InetSocketAddress(8888));
        // 4. 配置非阻塞方式
        serverSocketChannel.configureBlocking(false);
        // 5. Selector选择器注册ServerSocketChannel通道,绑定连接操作
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        // 6. 循环执行:监听连接事件及读取数据操作
        while (true) {
            // 6.1 监控客户端连接:selecto.select()方法返回的是客户端的通道数,如果为0,则说明没有客户端连接。
            if (selector.select(2000) == 0) {
                System.out.println("服务端等待客户端连接中~");
                continue;
            }
            // 6.2 得到SelectionKey,判断通道里的事件
            Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
            // 遍历所有SelectionKey
            while (keyIterator.hasNext()) {
                SelectionKey key = keyIterator.next();
                // 客户端连接请求事件
                if (key.isAcceptable()) {
                    System.out.println("服务端处理客户端连接事件:OP_ACCEPT");
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);
                    // 服务端建立与客户端之间的连接通道 SocketChannel,并且将该通道注册到 Selector 中,监听该通道的读事件
                    socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                }
                // 读取客户端数据事件
                if (key.isReadable()) {
                    // 数据在通道中,先拿到通道
                    SocketChannel channel = (SocketChannel) key.channel();
                    // 取到一个缓冲区,nio读写数据都是基于缓冲区。
                    ByteBuffer buffer = (ByteBuffer) key.attachment();
                    // 从通道中将客户端发来的数据读到缓冲区
                    channel.read(buffer);
                    System.out.println("客户端数据长度:" + buffer.array().length);
                    System.out.println("客户端发来数据:" + new String(buffer.array()));
                }
                //  6.3 手动从集合中移除当前key,防止重复处理
                keyIterator.remove();
            }
        }
    }
}

客户端:

public class NIOClient {
    public static void main(String[] args) throws Exception {
        // 1. 得到一个网络通道
        SocketChannel channel = SocketChannel.open();
        // 2. 设置非阻塞方式
        channel.configureBlocking(false);
        // 3. 提供服务器端的IP地址和端口号
        InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8888);
        // 4. 连接服务器端,如果用connect()方法连接服务器不成功,则用finishConnect()方法进行连接
        if (!channel.connect(address)) {
            // 因为接需要花时间,所以用while一直去尝试连接。在连接服务端时还可以做别的事,体现非阻塞。
            while (!channel.finishConnect()) {
                // nio 作为非阻塞式的优势,如果服务器没有响应(不启动服务端),客户端不会阻塞,最后会报错,客户端尝试连接服务器连不上。
                System.out.println("客户端等待连接建立时,执行其他任务~");
            }
        }
        // 5. 得到一个缓冲区并存入数据
        String msg = "客户端发送消息:hello";
        ByteBuffer writeBuf = ByteBuffer.wrap(msg.getBytes());
        // 6. 发送数据
        channel.write(writeBuf);
        // 阻止客户端停止,否则服务端也会停止。
        System.in.read();
    }
}

AIO

JDK 7 引入了 Asynchronous IO,即 AIO,叫做异步不阻塞的 IO,也可以叫做 NIO2

在进行 IO 编程中,常用到两种模式:Reactor模式 和 Proactor 模式

  • NIO采用 Reactor 模式,当有事件触发时,服务器端得到通知,进行相应的处理
  • AIO采用 Proactor 模式,引入异步通道的概念,简化了程序编写,一个有效的请求才启动一个线程,它的特点是先由操作系统完成后,才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间较长的应用

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

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

相关文章

三防平板|手持终端PDA|8寸/10寸工业三防平板电脑主板方案定制

近年来&#xff0c;随着科技的快速发展&#xff0c;三防平板成为了各行各业中不可或缺的工具。三防平板采用IP67级别的防护设计&#xff0c;通过了多项测试标准&#xff0c;如国标和美标&#xff0c;具备防水、防摔、防尘、防撞、防震、防跌落以及防盐雾等多重防护功能。因此&a…

CCKS2023-面向金融领域的主体事件检测-亚军方案分享

赛题分析 大赛地址 https://tianchi.aliyun.com/competition/entrance/532098/introduction?spma2c22.12281925.0.0.52b97137bpVnmh 任务描述 主体事件检测是语言文本分析和金融领域智能应用的重要任务之一&#xff0c;如在金融风控领域往往会对公司主体进行风险事件的检测…

microblaze仿真

verdivcs (1) vlogan/vcs增加编译选项 -debug_accessall -kdb -lca (2) 在 simulation 选项中加入下面三个选项 -guiverdi UVM_VERDI_TRACE"UVM_AWARERALHIERCOMPWAVE" UVM_TR_RECORD 这里 -guiverdi是启动verdi 和vcs联合仿真。UVM_VERDI_TRACE 这里是记录 U…

计算机存储单位 + 程序编译过程

C语言的编译过程 计算机存储单位 头文件包含的两种方式 使用 C/C 程序常用的IDE 常用的C语言编译器&#xff1a; 在选择编译器时&#xff0c;需考虑平台兼容性、性能优化、调试工具和开发人员的个人偏好等因素。 详细教程可转 爱编程的大丙

C++特性之多态

C作为面向对象的语言&#xff0c;三大特性之一多态在平时的编程中使用频率特别高。 本篇文章就来详细讲解一下多态。 什么是多态 不同的对象做相同的一件事会出现不同的状态&#xff0c;这就是多态。 举个列子&#xff1a;比如普通人买车票要全价购买&#xff0c;而军人只用半…

POJ 3735 Training little cats 动态规划(矩阵的幂)

一、题目大意 我们有N只猫&#xff0c;每次循环进行K次操作&#xff08;N<100&#xff0c;K<100&#xff09;&#xff0c;每次操作可有以下三种选择&#xff1a; 1、g i 给第i只猫1个食物 2、e i 让第i只猫吃完它所有的食物 3、s i j 交换第i和j只猫的食物。 求出M次…

【池式组件】线程池的原理与实现

线程池的原理与实现 线程池简介1.线程池1.线程池2.数量固定的原因3.线程数量如何确定4.为什么需要线程池5.线程池结构 线程池的实现数据结构设计1.任务结构2.任务队列结构3.线程池结构 接口设计 线程池的应用reactorredis 中线程池skynet 中线程池 线程池简介 1.线程池 1.线程…

ABP vNext 扩展 CurrentUser

ABP内置Users表&#xff0c;我们可以对其字段进行扩展&#xff0c;辅助进行更详细的数据记录 ICurrentUser 是主要的服务,用于获取有关当前活动的用户信息. 以下是 ICurrentUser 接口的基本属性:1. IsAuthenticated 如果当前用户已登录(已认证),则返回 true. 如果用户尚未登录…

软件设计师——面向对象技术(一)

&#x1f4d1;前言 本文主要是【面向对象技术】——软件设计师—面向对象技术的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#…

每日一练2023.12.8—— 稳赢【PTA】

题目链接&#xff1a; L1-044 稳赢 题目要求&#xff1a; 大家应该都会玩“锤子剪刀布”的游戏&#xff1a;两人同时给出手势&#xff0c;胜负规则如图所示&#xff1a; 现要求你编写一个稳赢不输的程序&#xff0c;根据对方的出招&#xff0c;给出对应的赢招。但是&#xff…

正则表达式(7):转义符

正则表达式&#xff08;7&#xff09;&#xff1a;正则表达式&#xff08;5&#xff09;&#xff1a;转义符 本博文转载自 此处&#xff0c;我们来认识一个常用符号&#xff0c;它就是反斜杠 “\” 反斜杠有什么作用呢&#xff1f;先不着急解释&#xff0c;先来看个小例子。 …

Python random模块及用法

random 模块主要包含生成伪随机数的各种功能变量和函数。 在 Python 的交互式解释器中先导入 random 模块&#xff0c;然后输入 random.__all__ 命令&#xff08;__all__ 变量代表了该模块开放的公开接口&#xff09;&#xff0c;即可看到该模块所包含的全部属性和函数&#x…

【分享】我想上手机器学习

目录 前言 一、理解机器学习 1.1 机器学习的目的 1.2 机器学习的模型 1.3 机器学习的数据 二、学习机器学习要学什么 2.1 学习机器学习的核心内容 2.2 怎么选择模型 2.3 怎么获取训练数据 2.4 怎么训练模型 三、机器学习的门槛 3.1 机器学习的第一道门槛 3.2 机器…

ES-环境安装(elasticsearch:7.17.9,kibana,elasticsearch-head)

ES 环境搭建 1 拉取镜像 常用三件套 docker pull kibana:7.17.9 docker pull elasticsearch:7.17.9 docker pull mobz/elasticsearch-head:52 启动镜像 elasticsearch 安装 这里可以先不挂载文件启动一波&#xff0c;然后把容器里的文件拷贝出来 docker run -p 19200:9200 …

[oeasy]python0002_终端_CLI_GUI_编程环境_游戏_真实_元宇宙

回忆 上次 了解了 python 语言的特点 历史悠久功能强大深受好评已成趋势 3大主流操作系统 macwindowslinux 我们 选择 linux 作为基础系统 为什么选择 黑乎乎的命令行界面呢&#xff1f;&#x1f914; GUI vs CLI 个人电脑 用图标和菜单组成 图形界面(GUI) Graphic User I…

Numpy数组的重塑,转置与切片 (第6讲)

Numpy数组的重塑,转置与切片 (第6讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…

朴素贝叶斯 朴素贝叶斯原理

朴素贝叶斯 朴素贝叶斯原理 判别模型和生成模型 监督学习方法又分生成方法 (Generative approach) 和判别方法 (Discriminative approach)所学到的模型分别称为生成模型 (Generative Model) 和判别模型 (Discriminative Model)。 朴素贝叶斯原理 朴素贝叶斯法是典型的生成学习…

鸿蒙OS应用开发之最简单的程序

鸿蒙OS应用开发之最简单的程序 前面介绍怎么样安装鸿蒙应用开发的环境&#xff0c;然后试着运行起来&#xff0c;并安装运行的虚拟机&#xff0c;以及对应9.0版本的API和SDK等软件。这样就具备了基本的开发基础&#xff0c;就可以进入创建应用程序开发了。 在我们起飞之前&…

【Java基础系列】Cron表达式入门

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

通过kubeadm方式安装k8s

虚拟机最少是 2 core&#xff0c;master内存最小3G&#xff0c;node内存最小2G. 要求的Docker版本是18.03&#xff0c;如果不是安装的docker ce&#xff0c;版本是过旧的&#xff0c;可以选择删除后重新安装&#xff1b; 也可以重新创建一个虚拟机执行以下命令。 简单方法&am…