java nio 原理 非阻塞IO Netty
一、为什么必须去了解NIO
首先你需要之后Netty的主要实现手段就是Nio,很多人一直学不明白Netty,根本原因是 除了日常开发中很难能够实践,很大一部分原因是不熟悉NIO,事实上真正熟悉了NIO和它背后的原理之后,去查看Netty的源码就有如神助!我们今天就从最基本的IO、以及NIO学起!
二、操作系统是如何定义I/O的
I/O相关的操作,详细各位从事java的人员并不陌生,顾名思义也就是Input/Output,对应着连个动词,Read/Write 读写两个动作,但是在上层系统应用中无论是读还是写,操作系统都不会直接的操作物理机磁盘数据,而是由系统内核加载磁盘数据!我们以Read为例,当程序中发起了一个Read请求后,操作系统会将数据从内核缓冲区加载到用户缓冲区,如果内核缓冲区内没有数据,内核会将该次读请求追加到请求队列,当内核将磁盘数据读取到内核缓冲区后,再次执行读请求,将内核缓冲区的数据复制到用户缓冲区,继而返回给上层应用系统!
三、网络编程中的IO模型
本文旨在让初学者先大致了解一下基本原理,所以这里并不会涉及到太多代码,具体的实现逻辑,可以关注后续源码分析的时候的文章,这里只做一个铺垫,为日后的学习做一个比较好的铺垫!
1. 同步阻塞I/O
I. 传统的阻塞IO模型
这种模型是单线程应用,服务端监听客户端连接,当监听到客户端的连接后立即去做业务逻辑的处理,该次请求没有处理完成之前,服务端接收到的其他连接全部阻塞不可操作!当然开发中,我们也不会这样写,这种写法只会存在于协议demo中!这种写法的缺陷在哪呢?
我们看图发现,当一个新连接被接入后,其他客户端的连接全部处于阻塞状态,那么当该客户端处理客户端时间过长的时候,会导致阻塞的客户端连接越来越多导致系统崩溃,我们是否能够找到一个办法,使其能够将业务处理与Accept接收新连接分离开来!这样业务处理不影响新连接接入就能够解决该问题!
II. 伪异步阻塞IO模型
这种业务模型是是对上一步单线程模型的一种优化,当一个新连接接入后,获取到这个链接的Socket,交给一条新的线程去处理,主程序继续接收下一个新连接,这样就能够解决同一时间只能处理一个新连接的问题,但是,明眼人都能看出来,这样有一个很致命的问题,这种模型处理小并发短时间可能不会出现问题,但是假设有10w连接接入,我需要开启10w个线程,这样会把系统直接压崩!我们需要限制线程的数量,那么肯定就会想到线程池,我们来优化一下这个模型吧!
III. 优化伪异步阻塞IO模型
这个模型是JDK1.4之前,没有NIO的时候的一个经典Socket模型,服务端接收到客户端新连接会后,将Socket连接以及业务逻辑包装为任务提交到线程池,由线程池开始执行,同时服务端继续接收新连接!这样能够解决上一步因为线程爆炸所引发的问题,但是我们回想下线程池的的提交步骤:当核心线程池满了之后会将任务放置到队列,当队列满了之后,会占用最大线程数的数量继续开启线程,当达到最大线程数的时候开始拒绝策略! 证明我最大的并发数只有1500个,其余的都在队列里面占1024个,假设现在的连接数是1w个,并且使用的是丢弃策略,那么会有近6000的连接任务被丢弃掉,而且1500个线程,线程之间的切换也是一个特别大的开销!这是一个致命的问题!
上述的三种模型除了有上述的问题之外,还有一个特别致命的问题,他是阻塞的!
在哪里阻塞的呢?
- 连接的时候,当没有客户端连接的时候是阻塞的!没有客户端连接的时候,线程只能傻傻的阻塞在哪里等待新连接接入!
- 等待数据写入的时候是阻塞的,当一个新连接接入后但是不写入数据,那么线程会一直等待数据写入,直到数据写入完成后才会停止阻塞! 假设我们使用 优化后的伪异步线程模型 ,1000个连接可能只有 100个连接会频繁写入数据,剩余900个连接都很少写入,那么就会有900个线程在傻傻等待客户端写入数据,所以,这也是一个很严重的性能开销!
现在我们总结一下上述模型的问题:
- 线程开销浪费严重!
- 线程间的切换频繁,效率低下!
- read/write执行的时候会进行阻塞!
- accept会阻塞等待新连接
那么,我们是否有一种方案,用很少的线程去管理成千上万的连接,read/write会阻塞进程,那么就会进入到下面的模型
2. 同步非阻塞I/O
同步非阻塞I/O模型就必须使用java NIO来实现了,看一段简单的代码:
public static void main(String[] args) throws IOException {//新接连池List<SocketChannel> socketChannelList = new ArrayList<>(8);//开启服务端SocketServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(8098));//设置为非阻塞serverSocketChannel.configureBlocking(false);while (true) {//探测新连接,由于设置了非阻塞,这里即使没有新连接也不会阻塞,而是直接返回nullSocketChannel socketChannel = serverSocketChannel.accept();//当返回值不为null的时候,证明存在新连接if(socketChannel!=null){System.out.println("新连接接入");//将客户端设置为非阻塞 这样read/write不会阻塞socketChannel.configureBlocking(false);//将新连接加入到线程池socketChannelList.add(socketChannel);}//迭代器遍历连接池Iterator<SocketChannel> iterator = socketChannelList.iterator();while (iterator.hasNext()) {ByteBuffer byteBuffer = ByteBuffer.allocate(128);SocketChannel channel = iterator.next();//读取客户端数据 当客户端数据没有写入完成的时候也不会阻塞,长度为0int read = channel.read(byteBuffer);if(read > 0) {//当存在数据的时候打印数据System.out.println(new String(byteBuffer.array()));}else if(read == -1) {//客户端退出的时候删除该连接iterator.remove();System.out.println("断开连接");}}}
}
上述代码我们可以看到一个关键的逻辑:serverSocketChannel.configureBlocking(false); 这里被设置为非阻塞的时候无论是 accept还是read/write都不会阻塞!具体的为什么会非阻塞,我放到文章后面说,我们看一下这种的实现逻辑有什么问题!
看这里,我们似乎的确使用了一条线程处理了所有的连接以及读写操作,但是假设我们有10w连接,活跃连接(经常read/write)只有1000,但是我们这个线程需要每次否轮询10w条数据处理,极大的消耗了CPU!
我们期待什么? 期待的是,每次轮询值轮询有数据的Channel, 没有数据的就不管他,比如刚刚的例子,只有1000个活跃连接,那么每次就只轮询这1000个,其他的有读写了有数据就轮询,没读写就不轮询!
3. 多路复用模型
多路复用模型是JAVA NIO 推荐使用的经典模型,内部通过 Selector进行事件选择,Selector事件选择通过系统实现,具体流程看一段代码:
public static void main(String[] args) throws IOException {//开启服务端SocketServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(8098));//设置为非阻塞serverSocketChannel.configureBlocking(false);//开启一个选择器Selector selector = Selector.open();serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);while (true) {// 阻塞等待需要处理的事件发生selector.select();// 获取selector中注册的全部事件的 SelectionKey 实例Set<SelectionKey> selectionKeys = selector.selectedKeys();//获取已经准备完成的keyIterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {SelectionKey next = iterator.next();//当发现连接事件if(next.isAcceptable()) {//获取客户端连接SocketChannel socketChannel = serverSocketChannel.accept();//设置非阻塞socketChannel.configureBlocking(false);//将该客户端连接注册进选择器 并关注读事件socketChannel.register(selector, SelectionKey.OP_READ);//如果是读事件}else if(next.isReadable()){ByteBuffer allocate = ByteBuffer.allocate(128);//获取与此key唯一绑定的channelSocketChannel channel = (SocketChannel) next.channel();//开始读取数据int read = channel.read(allocate);if(read > 0){System.out.println(new String(allocate.array()));}else if(read == -1){System.out.println("断开连接");channel.close();}}//删除这个事件iterator.remove();}}
}
相比上面的同步非阻塞IO,这里多了一个selector选择器,能够对关注不同事件的Socket进行注册,后续如果关注的事件满足了条件的话,就将该socket放回到到里面,等待客户端轮询!
NIO底层在JDK1.4版本是用linux的内核函数select()或poll()来实现,跟上面的NioServer代码类似,selector每次都会轮询所有的sockchannel看下哪个channel有读写事件,有的话就处理,没有就继续遍历,JDK1.5开始引入了epoll基于事件响应机制来优化NIO,首先我们会将我们的SocketChannel注册到对应的选择器上并选择关注的事件,后续操作系统会根据我们设置的感兴趣的事件将完成的事件SocketChannel放回到选择器中,等待用户的处理!那么它能够解决上述的问题吗?
肯定是可以的,因为上面的一个同步非阻塞I/O痛点在于CPU总是在做很多无用的轮询,在这个模型里被解决了!这个模型从selector中获取到的Channel全部是就绪的,后续只需要也就是说他每次轮询都不会做无用功!
深入 底层概念解析
select模型
如果要深入分析NIO的底层我们需要逐步的分析,首先,我们需要了解一种叫做select()函数的模型,它是什么呢?他也是NIO所使用的多路复用的模型之一,是JDK1.4的时候所使用的一种模型,他是epoll模型之前所普遍使用的一种模型,他的效率不高,但是当时被普遍使用,后来才会被人优化为epoll!
他是如何做到多路复用的呢?如图:
- 首先我们需要了解操作系统有一个叫做工作队列的概念,由CPU轮流执行工作队列里面的进程,我们平时书写的Socket服务端客户端程序也是存在于工作队列的进程中,只要它存在于工作队列,它就会被CPU调用执行!我们下文将该网络程序称之为进程A
2.他的内部会维护一个 Socket列表,当调用系统函数select(socket[])的时候,操作系统会将进程A加入到Socket列表中的每一个Socket的等待队列中,同时将进程A从工作队列移除,此时,进程A处于阻塞状态!
3.当网卡接收到数据之后,触发操作系统的中断程序,根据该程序的Socket端口取对应的Socket列表中寻找该进程A,并将进程A从所有的Socket列表中的等待队列移除,并加入到操作系统的工作队列!
4.此时进程A被唤醒,此时知道至少有一个Socket存在数据,开始依次遍历所有的Socket,寻找存在数据的Socket并进行后续的业务操作
该种结构的核心思想是,我先让所有的Socket都持有这个进程A的引用,当操作系统触发Socket中断之后,基于端口寻找到对应的Socket,就能够找到该Socket对应的进程,再基于进程,就能够找到所有被监控的Socket! 要注意,当进程A被唤醒,就证明一件事,操作系统发生了Socket中断,就至少有一个Socket的数据准备就绪,只需要将所有的Socket遍历,就能够找到并处理本次客户端传入的数据!
但是,你会发现,这种操作极为繁琐,中间似乎存在了很多遍历,先将进程A加入的所有的Socket等待队列需要遍历一次,发生中断之后需要遍历一次Socket列表,将所有对于进程A的引用移除,并将进程A的引用加入到工作队列!因为此时进程A并不知道哪一个Socket是有数据的,所以,由需要再次遍历一遍Socket列表,才能真正的处理数据,整个操作总共遍历了3此Socket,为了保证性能,所以1.4版本种,最多只能监控1024个Socket,去掉标准输出输出和错误输出只剩下1021个,因为如果Socket过多势必造成每次遍历消耗性能极大!
epoll模型
epoll总共分为三个比较重要的函数:
- epoll_create 对应JDK NIO代码种的Selector.open()
- epoll_ctl 对应JDK NIO代码中的socketChannel.register(selector,xxxx);
- epoll_wait 对应JDK NIO代码中的 selector.select();
感兴趣的可以下载一个open-jdk-8u的源代码,也可以关注公众号回复openJdk获取源码压缩包!
他是如何优化select的呢?
-
epoll_create:这些系统调用将返回一个非负文件描述符,他也和Socket一样,存在一个等待队列,但是,他还存在一个就绪队列!
2.epoll_ctl :添加Socket的监视,对应Java中将SocketChannel注册到Selector中,他会将创建的文件描述符的引用添加到Socket的等待队列!这点比较难理解,注意是将EPFD(Epoll文件描述符)放到Socket的等待队列!
3.当操作系统发生中断程序后,基于端口号(客户端的端口号是唯一的)寻找到对应的Socket,获取到EPFD的引用,将该Socket的引用加入到EPFD的就序列表!
4.epoll_wait:查看EPFD的就绪列表是否存在Socket的引用,如果存在就直接返回,不存在就将进程A加入到EPFD的等待队列,并移除进程A再工作队列的引用!
当网卡再次接收到数据,发生中断,进行上述步骤,将该Socket的因引用加入到就序列表,并唤醒进程A,移除该EPFD等待队列的进程A,将进程A加入到工作队列,程序继续执行!
4. 异步非阻塞I/O
异步非阻塞模型是用户应用只需要发出对应的事件,并注册对应的回调函数,由操作系统完成后,回调回调函数,完成具体的约为操作!先看一段代码
public static void main(String[] args) throws Exception {final AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(9000));//监听连接事件,并注册回调serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {@Overridepublic void completed(AsynchronousSocketChannel socketChannel, Object attachment) {try {System.out.println("2--"+Thread.currentThread().getName());// 再此接收客户端连接,如果不写这行代码后面的客户端连接连不上服务端serverChannel.accept(attachment, this);System.out.println(socketChannel.getRemoteAddress());ByteBuffer buffer = ByteBuffer.allocate(1024);//监听read事件并注册回调socketChannel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {@Overridepublic void completed(Integer result, ByteBuffer buffer) {System.out.println("3--"+Thread.currentThread().getName());buffer.flip();System.out.println(new String(buffer.array(), 0, result));//向客户端回写一个数据socketChannel.write(ByteBuffer.wrap("HelloClient".getBytes()));}//发生错误调这个@Overridepublic void failed(Throwable exc, ByteBuffer buffer) {exc.printStackTrace();}});} catch (IOException e) {e.printStackTrace();}}//发生错误调这个@Overridepublic void failed(Throwable exc, Object attachment) {exc.printStackTrace();}});System.out.println("1--"+Thread.currentThread().getName());Thread.sleep(Integer.MAX_VALUE);}
}
AIO客户端
public static void main(String... args) throws Exception {AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();socketChannel.connect(new InetSocketAddress("127.0.0.1", 9000)).get();socketChannel.write(ByteBuffer.wrap("HelloServer".getBytes()));ByteBuffer buffer = ByteBuffer.allocate(512);Integer len = socketChannel.read(buffer).get();if (len != -1) {System.out.println("客户端收到信息:" + new String(buffer.array(), 0, len));}
}
整体逻辑就是,告诉系统我要关注一个连接的事件,如果有连接事件就调用我注册的这个回调函数,回调函数中获取到客户端的连接,然后再次注册一个read请求,告诉系统,如果有可读的数据就调用我注册的这个回调函数!当存在数据的时候,执行read回调,并写出数据!
相关文章:
java nio 原理 非阻塞IO Netty
一、为什么必须去了解NIO 首先你需要之后Netty的主要实现手段就是Nio,很多人一直学不明白Netty,根本原因是 除了日常开发中很难能够实践,很大一部分原因是不熟悉NIO,事实上真正熟悉了NIO和它背后的原理之后,去查看Netty的源码就有…...
【ClickHouse】Ubuntu下离线安装ClickHouse数据库并使用DBeaver连接
目录 0. 安装前准备1 安装ClickHouse1.1 下载安装包1.2 离线安装1.3 配置密码1.4 启动ClickHouse服务 2 DBeaver连接配置2.1 下载ClickHouse驱动2.2 DBeaver配置2.2.1 配置主要参数2.2.2 配置驱动 2.3 常见问题处理2.3.1 修改远程登录配置2.3.2 更新驱动配置 0. 安装前准备 有…...
vue2打包带路径的项目,刷新404问题解决
问题描述 Vue 2 项目打包时设置了 publicPath: /web/,并通过 Nginx 配置访问 http://ip/web 时可以正常加载首页,但刷新页面时出现 404 错误 原nginx的配置 location /web {alias /www/dist; # 静态文件地址try_files $uri $uri/ /index.html;index i…...
【计算机视觉】文本识别
计算机视觉,广义的文本识别是指对输入的图像进行分析处理,识别出图像中的文字信息,这里的图像可以使传统的文档图像,也可以是现实世界中的场景图像。 简介 无论是传统方法还是基于深度深度学习的方法,完整的文本识别…...
Vue和React的区别
组件开发方式: Vue 使用单文件组件(SFC), HTML, JS 和 CSS 在一个文件内实现 <template><div class"my-component"><!-- HTML模板 --></div> </template><script> export default {// JavaScr…...
STM32 是什么?同类产品有哪些
STM32 是什么? STM32 是由意法半导体(STMicroelectronics)推出的基于 ARM Cortex-M 内核 的 32 位微控制器(MCU)系列。它专为高性能、低功耗的嵌入式应用设计,广泛应用于以下领域: 工业控制&am…...
Git学习使用笔记
目录 一、基本介绍 1.1 版本控制 1.2 版本控制软件的基础功能 1.3 多人协作开发/集中式版本控制 1.4 分布式版本控制 二、Git安装 2.1下载git 2.2 使用Github Desktop软件 2.2.1 创建本地仓库 2.2.2 删除本地仓库 2.2.3 仓库文件操作 2.2.4 多人协作 2.2.4.1 分…...
Bash 中的运算方式
目录 概述: 1. (()) 运算符 2. let 命令 3. expr 命令 4. $[] 直接运算 5. bc(计算器,支持浮点数) 6. awk(强大的文本处理工具,也可计算) 概述: Bash 本身只支持整数运算&am…...
NLP Word Embeddings
Word representation One-hot形式 在上一周介绍RNN类模型时,使用了One-hot向量来表示单词的方式。它的缺点是将每个单词视为独立的,算法很难学习到单词之间的关系。 比如下面的例子,即使语言模型已经知道orange juice是常用组合词…...
Unity UI个人总结
个人总结,太简单的直接跳过。 一、缩放模式 1.固定像素大小 就是设置一个100x100的方框,在1920x1080像素下在屏幕中长度占比1/19,在3840x2160,方框在屏幕中长度占比1/38。也就是像素长款不变,在屏幕中占比发生变化 2.…...
开发基础(8):鸿蒙图表开发
mpchart mpchart是一个包含各种类型图表的图表库,主要用于业务数据汇总,例如销售数据走势图,股价走势图等场景中使用,方便开发者快速实现图表UI,mpchart主要包括线形图、柱状图、饼状图、蜡烛图、气泡图、雷达图、瀑布图等自定义图表库。 柱状图 导入import {BarChart, …...
Vue的简单入门 一
声明:本版块根据B站学习,创建的是vue3项目,用的是vue2语法风格,仅供初学者学习。 目录 一、Vue项目的创建 1.已安装15.0或更高版本的Node.js 2.创建项目 二、 简单认识目录结构 三、模块语法中的指令 1.v-html 1.文本插值…...
vs2022支持.netframework4.0
下载nuget包 .netframework4.0 解压nuget 复制到C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework 参考 https://www.cnblogs.com/bdqczhl/p/18670152 https://blog.csdn.net/xiaomeng1998_/article/details/135979884...
[前端] axios网络请求二次封装
一、场景描述 为什么要对axios网络请求进行二次封装? 解决代码的复用,提高可维护性。 —这个有两个方案:一个是二次封装一个是实例化。(设置一些公共的参数,然后进行请求) 为什么可以解决代码的复用: 这是…...
前端包管理器的发展以及Npm、Yarn和Pnpm对比
在现代前端开发中,包管理器是不可或缺的核心工具。随着 JavaScript 生态的快速发展,开发者经历了从 npm 一统天下到 Yarn 挑战格局,再到 pnpm 创新突破的技术演进。这里将对三种主流包管理器(npm/Yarn/pnpm)进行全方位…...
城电科技| 光伏太阳花:让绿色能源随处绽放
在追求绿色可持续发展的今天,清洁能源设备不断涌现,城电科技的光伏太阳花便是其中的佼佼者。它不仅造型独特美观,更凭借出色的性能,在多个场景中都能发挥重要作用。那么,这款神奇的光伏太阳花究竟适合安装在哪里呢&…...
LVS集群(DR/NAT)
特性NAT 模式DR 模式工作原理Director 修改请求/响应的 IP 地址和端口,流量双向经过 DirectorDirector 仅修改请求的 MAC 地址,响应由 Real Server 直接返回客户端性能较低(需处理双向流量,易成瓶颈)高(仅处…...
保姆级GitHub大文件(100mb-2gb)上传教程
GLF(Git Large File Storage)安装使用 使用GitHub desktop上传大于100mb的文件时报错 The following files are over 100MB. lf you commit these files, you will no longer beable to push this repository to GitHub.com.term.rarWe recommend you a…...
【Jenkins流水线搭建】
Jenkins流水线搭建 01、SpringBoot项目 - Jenkins基于Jar持续集成搭建文档基于手动方式发布项目基于dockerfile基于jenkins + dockerfile + jenkinsfile +pieline基于jenkins + jar方式的发布01、环境说明01、准备项目02、准备服务器03、安装git04、安装jdk1.805、安装maven依赖…...
linux 安装ftp
1、安装vsftpd sudo yum install -y vsftpd 2、运行以下命令,启动FTP服务,并设置开机自启动。 sudo systemctl start vsftpdsudo systemctl enable vsftpd 3、运行以下命令,查看FTP服务监听的端口。 sudo netstat -antup | grep ftp 出现…...
DDoS技术解析
这里是Themberfue 今天我们不聊别的,我们聊聊著名的网络攻击手段之一的 DDoS,看看其背后的技术细节。 DoS 了解 DDoS 前,先来讲讲 DoS 是什么,此 DoS 而不是 DOS 操作系统啊。1996年9月6日,世界第三古老的网络服务提供…...
移远通信边缘计算模组成功运行DeepSeek模型,以领先的工程能力加速端侧AI落地
近日,国产大模型DeepSeek凭借其“开源开放、高效推理、端侧友好”的核心优势,迅速风靡全球。移远通信基于边缘计算模组SG885G,已成功实现DeepSeek模型的稳定运行,并完成了针对性微调。 目前,该模型正在多款智能终端上进…...
Linux | 进程相关概念(进程、进程状态、进程优先级、环境变量、进程地址空间)
文章目录 进程概念1、冯诺依曼体系结构2、进程2.1基本概念2.2描述进程-PCB2.3组织进程2.4查看进程2.5通过系统调用获取进程标识符2.6通过系统调用创建进程-fork初识fork の 头文件与返回值fork函数的调用逻辑和底层逻辑 3、进程状态3.1状态3.2进程状态查看命令3.2.1 ps命令3.2.…...
站群服务器和普通服务器有哪些不同之处?
站群服务器是一个集中管理工具,可以允许网站管理员同时管理多个网站,但是不要管理员登录每一个网站的后台,在站群模式下,网站管理员通过一个或者多个服务器来托管大量的子站点,可以支持大规模网站的集中管理和优化。 普…...
百度千帆平台对接DeepSeek官方文档
目录 第一步:注册账号,开通千帆服务 第二步:创建应用,获取调用秘钥 第三步:调用模型,开启AI对话 方式一:通过API直接调用 方式二:使用SDK快速调用 方式三:在千帆大模…...
DeepSeek帮助解决Oracle死锁问题
最近在生产上遇到一个死锁问题,Oracle 抛出了 ORA-000060 异常。 业务场景:程序按行读取一个上游系统送的文件数据(大概有几万行),读取到数据后,每 500 行分配给一个线程去批量更新数据库(使用…...
MySQL无法连接到本地localhost的解决办法2024.11.8
问题描述:我的MySQL可以远程连接服务器,但无法连接自己的localhost。 错误提示: 2003 - Cant connet to MySQL server on localhost(10061 "Unknown error")查找问题原因: 1. 检查环境变量是否正确:发现没…...
Nginx之rewrite重写功能
目录 一、rewrite概述 1、rewrite功能 2、跳转场景 二、标准配置指令 1、rewrite日志记录指令 2、未初始化变量告警日志记录指令 3、rewrite 指令 3.1 正则表达式 三、rewrite模块使用实例 1.基于域名的跳转 2.基于客户端 IP 访问跳转 3.?基于旧域名跳转到新域名后…...
Selenium WebDriver自动化测试(扩展篇)--Jenkins持续集成
文章目录 一、引言二、Jenkins简介三、安装部署Jenkins安装部署四、集成Git与Maven安装必要的插件配置Git配置Maven五、创建Job创建自由风格的项目配置源码管理配置构建触发器配置构建环境配置构建步骤配置Post-build Actions六、触发构建示例:GitHub Webhook触发构建七、封装…...
MyBatis拦截器终极指南:从原理到企业级实战
在本篇文章中,我们将深入了解如何编写一个 MyBatis 拦截器,并通过一个示例来展示如何在执行数据库操作(如插入或更新)时,自动填充某些字段(例如 createdBy 和 updatedBy)信息。本文将详细讲解拦…...
DeepSeek4j 已开源,支持思维链,自定义参数,Spring Boot Starter 轻松集成,快速入门!建议收藏
DeepSeek4j Spring Boot Starter 快速入门 简介 DeepSeek4j 是一个专为 Spring Boot 设计的 AI 能力集成启动器,可快速接入 DeepSeek 大模型服务。通过简洁的配置和易用的 API,开发者可轻松实现对话交互功能。 环境要求 JDK 8Spring Boot 2.7Maven/Gr…...
linux 板子的wifi模块连上路由器后,用udhcpc给板子wifi分配ip,udhcpc获取到ip,但没有写入wlan0网卡上
linux 板子的wifi模块连上路由器后,用udhcpc给板子wifi分配ip,udhcpc获取到ip,但没有写入wlan0网卡上 这里的问题是 /usr/share/udhcpc/default.script脚本有问题 用下面正确脚本,即可写进去 #!/bin/sh# udhcpc script for busybox # Copyr…...
【工业安全】-CVE-2022-35555- Tenda W6路由器 命令注入漏洞
文章目录 1.漏洞描述 2.环境搭建 3.漏洞复现 4.漏洞分析 4.1:代码分析 4.2:流量分析 5.poc代码: 1.漏洞描述 漏洞编号:CVE-2022-35555 漏洞名称:Tenda W6 命令注入 威胁等级:高危 漏洞详情࿱…...
twisted实现MMORPG 游戏数据库操作封装设计与实现
在设计 MMORPG(大规模多人在线角色扮演游戏)时,数据库系统是游戏架构中至关重要的一部分。数据库不仅承担了游戏中各种数据(如玩家数据、物品数据、游戏世界状态等)的存储和管理任务,还必须高效地支持并发访…...
【MySQL】基础篇
1. MySQL中的NULL值是怎么存放的? MySQL的compact行格式中会用【NULL值列表】来标记值为NULL的列,NULL值不会存储在行格式中的真实数据部分。 NULL值列表会占用1字节空间,当表中所有字段都被定义成NOT NULL,行格式中就不会有NULL值…...
【自学笔记】机器学习基础知识点总览-持续更新
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 机器学习重点知识点总览一、机器学习基础概念二、机器学习理论基础三、机器学习算法1. 监督学习2. 无监督学习3. 强化学习 四、机器学习处理流程五、机器学习常见问…...
记录阿里云CDN配置
网站接入CDN全流程,共4步!-阿里云开发者社区 1、开通阿里云CDN服务 2、添加加速域名 3、验证域名归属权 4、域名添加CDN生成的CNAME解析 按照官网描述增加。细节点: 1. 域名和泛域名区别 2.开启https,要用nginx的证书,和项…...
同为科技智能PDU助力Deepseek人工智能和数据交互的快速发展
1 2025开年,人工智能领域迎来了一场前所未有的变革。Deepseek成为代表“东方力量”的开年王炸,不仅在国内掀起了技术热潮,并且在全球范围内引起了高度关注。Deepseek以颠覆性技术突破和现象级应用场景席卷全球,这不仅重塑了产业格…...
聚铭网络入围2025年度江苏省政府采购信息安全设备协议供货名单
近日,2025年度江苏省党政机关、事业单位及团体组织信息安全设备框架协议采购项目入围结果公布。聚铭网络凭借自身专业实力和技术优势脱颖而出,成功入围22个分包。 此次采购项目是江苏省政府采购领域级别最高、覆盖面最广的项目之一。从资格评选到后期材料…...
【Linux】--- 基础开发工具之yum/apt、vim、gcc/g++的使用
Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏: Linux网络编程 本篇博客我们来认识一下Linux中的一些基础开发工具 --- yum,vim,gcc/g。 🏠 yum 🎸 什么是yum 当用户想下载软…...
leetcode 297. 二叉树的序列化与反序列化
题目如下 我们常常说单独先序遍历不能完整的表示一棵树是有前提条件的。 为什么?先序遍历是按 根节点 左子树 右子树的方向遍历树且遇到空子树直接返回,这样会造成我们并不知道某个节点的左右子树存在与否,故我们无法确定树的形状。但是如果…...
OpenAI 放王炸,将发布整合多项技术的 GPT-5,并免费无限使用,该模型有哪些技术亮点
对于 ChatGPT 的免费用户,将可以无限制地访问 GPT-5,但仅限于标准的智能级别。该级别会设定滥用限制,以防止不当使用(意思就是你得付费嘛)。 OpenAI CEO Sam Altman 今天在 X 上透露了 GPT-4.5 和 GPT-5 的最新发展计划。 OpenAI 将发布代…...
Ubuntu22.04 使用useradd 创建用户时,没有创建家目录时,如何手动创建家目录
测试案例: 使用useradd不加参数创建test目录 如下可以看出使用 useradd 创建用户的时候默认不会创建家目录 rootlocal:~# useradd test rootlocal:~# id test uid1001(test) gid1001(test) groups1001(test) rootlocal:~# cat /etc/passwd | grep test test:x:1001:…...
浅聊Docker使用、部署
在Java面试中,当被问到关于Docker中间件的使用、部署及在实际项目中的考虑时,可以按照以下结构和内容来详细回答: 一、Docker中间件的使用 1. Docker是什么? Docker是一个开源平台,允许开发者将应用程序及其依赖项打…...
Java面试第一山!《集合》!
一、引言 在 Java 编程的世界里,数据的存储和处理是非常重要的环节。Java 集合框架就像是一个功能强大的工具箱,为我们提供了各种各样的数据结构来高效地存储和操作数据。今天,跟随小编一起来深入了解 Java 集合框架,这不仅有助于…...
力扣-二叉树-257 二叉树的所有路径
思路 除去根节点,每一层添加->val,然后使用前序遍历的顺序 代码 class Solution { public:vector<string> res;void getTreePaths(string s, TreeNode* root){s "->";s to_string(root->val);if(root->left nullptr &…...
异构计算架构助力智能座舱实现高效低耗体验
摘要: 随着智能汽车的飞速发展,智能座舱作为人车交互的核心区域,对算力、功耗及延迟等性能指标提出了严苛要求。异构计算架构凭借在硬件、软件与系统层面的深度优化,能显著提升智能座舱的算力利用率,降低功耗与延迟,为用户打造高效、低能耗的智能座舱体验。本文深入剖析…...
【vscode】VScode Remote SSH配置
VScode使用remote ssh 到服务器上的Docker容器中 1. 配置远程服务器docker容器的端口映射,例如将服务器的2222端口映射到container的22端口(默认) 1.1 在容器系统的sshd_config文件中配置参数 #配置文件 vim /etc/ssh/sshd_config #打开端口号 Port 221.2 建立容…...
急停信号的含义
前言: 大家好,我是上位机马工,硕士毕业4年年入40万,目前在一家自动化公司担任软件经理,从事C#上位机软件开发8年以上!我们在开发C#的运动控制程序的时候,一个必要的步骤就是确认设备按钮的急停…...
【Azure 架构师学习笔记】- Azure Databricks (11) -- UC搭建
本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Databricks】系列。 接上文 【Azure 架构师学习笔记】- Azure Databricks (10) – UC 使用 前言 由于ADB 的更新速度很快,在几个月之后重新搭建ADB 时发现UC 已经更新了很多,为了后续做ADB 的功…...