Java网络编程-深入理解BIO、NIO
深入理解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 时,数据是基于 Channel 和 Buffer 进行操作的,数据从 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. 绑定端口号8888System.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();// 遍历所有SelectionKeywhile (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 模式,引入异步通道的概念,简化了程序编写,一个有效的请求才启动一个线程,它的特点是先由操作系统完成后,才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间较长的应用
相关文章:
 
Java网络编程-深入理解BIO、NIO
深入理解BIO与NIO BIO BIO 为 Blocked-IO(阻塞 IO),在 JDK1.4 之前建立网络连接时,只能使用 BIO 使用 BIO 时,服务端会对客户端的每个请求都建立一个线程进行处理,客户端向服务端发送请求后,…...
 
ShenYu网关注册中心之HTTP注册原理
文章目录 1、客户端注册流程1.1、读取配置1.1.1、用于注册的 HttpClientRegisterRepository1.1.2、用于扫描构建 元数据 和 URI 的 SpringMvcClientEventListener 1.2、扫描注解,注册元数据和URI1.2.1、构建URI并写入Disruptor1.2.2、构建元数据并写入Disruptor1.2.…...
 
探索GameFi:区块链与游戏的未来融合
在过去的几年里,区块链技术逐渐渗透到各个领域,为不同行业带来了前所未有的变革。其中,游戏行业成为了一个引人注目的焦点,而这种结合被称为GameFi,即游戏金融。GameFi不仅仅是一个概念,更是一场区块链和游…...
 
Windows下使用CMake编译lua
Lua 是一个功能强大、高效、轻量级、可嵌入的脚本语言。它支持程序编程、面向对象程序设计、函数式编程、数据驱动编程和数据描述。 Lua的官方网站上只提供了源码,需要使用Make进行编译,具体的编译方法为 curl -R -O http://www.lua.org/ftp/lua-5.4.6.…...
 
【C语言(十一)】
C语言内存函数 一、memcpy使用和模拟实现 void * memcpy ( void * destination, const void * source, size_t num ); • 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。 • 这个函数在遇到 \0 的时候并不会停下来。 • 如果sourc…...
 
系统运行占用过高
1、CPU过高的问题排查 示例代码: public class Test { static class MyThread extends Thread { public void run() { // 死循环,消耗CPU int i 0; while (true) { i; } } } public static void main(String args[]) throws InterruptedException { ne…...
 
HTML---初识CSS
文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据总结 一.CSS概念 CSS是层叠样式表(Cascading Style Sheets)的缩写。它是一种用于描述HTML文档外观样式的标记语言。通过CSS,开发者可以在不改变HTML标记结构的情况…...
 
监控pod 容器外网请求网络带宽,过滤掉内网、基于k8spacket开发、prometheus开发export
首先安装k8spacket 安装k8spacket遇到问题,下载插件一直能不能下载成功,pod不能启动。所有手动下载处理。 helm repo add k8spacket https://k8spacket.github.io/k8spacket-helm-chart helm pull k8spacket/k8spacket打开values.yaml 文件 手动下载插…...
 
windows下docker环境安装
开启硬件虚拟化技术 win10中开启 Hyper-V Win10 下是否开启硬件虚拟化技术,在控制面板,启用 window 功能,找到 Hyper-V 选项,点勾选确认。如图: Windows 11 家庭中文版新增 Hyper-V选项 注意以下的解决方案来自win1…...
 
Python小程序 - 表格数值统计
题设:Excel表格中,计算如下图所示不同颜色(蓝、黄、桔)单元格值:各颜色填涂的单元格值的总和条件: - Excle表格中 - 分色标记,单元格有值 - 开始列(当前为D),…...
 
Unity | Shader基础知识(第一集:unity中最简单的shader)
目录 一、unity的shader 二、创建一个shader(在创建时,选前三种都可以) 三、内容解读 1.shader一直都在 2.我们写shader在写什么 四、没有被干预的shader(最简单的shader) 相关阅读 编写着色器概述 - Unity 手册…...
 
橘子学K8S01之容器中所谓的隔离
我们一直都在说容器就是一个沙盒,沙盒技术顾名思义就是像一个集装箱一样,把应用(服务,进程之类的)装起来的技术,这样每个进程在自己的沙盒中和其他的沙盒隔离开来,每个沙盒之间存在一个边界使得他们互不干扰࿰…...
 
利用svm进行模型训练
一、步骤 1、将文本数据转换为特征向量 : tf-idf 2、使用这些特征向量训练SVM模型 二、代码 from sklearn.model_selection import train_test_split from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.svm import SVC from sklearn.m…...
 
【Docker】WSL 2 上的 Docker 搭建和入门
▒ 目录 ▒ 🛫 导读开发环境 1️⃣ 安装安装Docker Desktop for Windows 2️⃣ 环境配置3️⃣ hello world第一次运行再次运行分析总结 📖 参考资料 🛫 导读 开发环境 版本号描述文章日期2023-12-14操作系统Win11 - 22H222621.2715WSL2 C:…...
pytorch环境配置
1.创建环境 conda create --name pytorch python3.11.5 2.激活环境 source activate pytorch 3.添加国内镜像源: conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https://mirrors.tuna.tsin…...
 
电子眼+无人机构建平安城市视频防控监控方案
电子眼(也称为监控摄像机)可以通过安装在城市的不同角落,实时监控城市的各个地方。它们可以用于监测交通违法行为、监控公共场所的安全以及实时监测特定区域的活动情况。通过电子眼的应用,可以帮助警方及时发现并响应各类安全事件…...
mysql binlog_ignore_db参数的效果详解
 我们知道 binlog 会记录数据库所有执行的 DDL 和 DML 语句(除了数据查询语句select、show等)。 我们可以在mysql配置文件中关闭binlog [mysqld] skip-log-bin注意默认情况下会记录所有库的操作,那么如果我们有另类需求,比如说只让某个库记录 binglog 或排除某个库记录…...
 
HI3559AV100和FPGA 7K690T的PCIE接口调试记录-续
上文https://blog.csdn.net/fzktongyong/article/details/134963814?spm1001.2014.3001.5501 上一篇文中PCIE实测速度和理论计算有较大偏差,经过尝试后有所提升。 1、提升效果 1)、RC写操作,实测速度817MB/s(410407&…...
vivado约束方法4
时序约束向导 定时约束向导确定合成或上缺少的定时约束实现的设计。它分析了网表、时钟网络连接和现有的定时限制,以便根据《超快设计方法指南》提供建议用于FPGA和SoC(UG949)。以下11涵盖了三类约束页面,然后是摘要。包括以下步…...
LeetBook学习-C语言-数组
1.数组的操作 1.1 读取元素 知道内存地址可以快速访问,时间复杂度为O(1) 1.2 查找元素 从首地址开始,逐个查找,最坏时间复杂度为O(N) 1.3 插入元素 插入元素,首先位置要腾空,而后执行插入操作。 1.4 删除元素 删除掉某…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
 
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
 
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
 
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
 
uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统
Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...
