编程技术是改变世界的力量。
本站
当前位置:网站首页 > 后端语言 > 正文

想理解Java的IO,不要从操作系统开始说起的都是耍流氓

gowuye 2024-04-04 11:53 2 浏览 0 评论

Java网络IO涵盖的知识体系很广泛,本文将简单介绍Java网络IO的相关知识

从操作系统开始

为了保护操作系统的安全,会将内存分为用户空间和内核空间两个部分。如果用户想要操作内核空间的数据,则需要把数据从内核空间拷贝到用户空间

举个栗子,如果服务器收到了从客户端过来的请求,并且想要进行处理,那么需要经过这几个步骤:

  • 服务器的网络驱动接收到消息之后,向内核申请空间,并在收到完整的数据包(这个过程会产生延时,因为有可能是通过分组传送过来的)后,将其复制到内核空间;
  • 数据从内核空间拷贝到用户空间;
  • 用户程序进行处理。

?

因此我们可以将服务器接收消息理解为两个阶段:

  • 等待数据到达
  • 将数据从内核空间拷贝到用户空间

在操作系统中的IO

在此以Linux操作系统为例。Linux是一个将所有的外部设备都看作是文件来操作的操作系统,在它看来:everything is a file,那么我们就把对于外部设备的操作都看作是对文件进行操作。而且我们对一个文件进行读写,都需要通过调用内核提供的系统调用。

而在Linux中,一个基本的IO会涉及到两个系统对象:一个是调用这个IO的进程对象(用户进程),另一个是系统内核。也就是说,当一个read操作发生时,将会经历这些阶段:

  • 通过read系统调用,向内核发送读请求;
  • 内核向硬件发送读指令,并等待读就绪;
  • DMA把将要读取的数据复制到指定的内核缓存区中;
  • 内核将数据从内核缓存区拷贝到用户进程空间中

在此期间会发生几种IO操作:

  • 同步IO:当用户发出IO请求操作后,内核会去查看要读取的数据是否就绪,如果没有,就一直等待。期间用户线程或内存会不断地轮询数据是否就绪。当数据就绪时,再把数据从内核拷贝到用户空间。
  • 异步IO:用户线程只需发出IO请求和接收IO操作完成通知,期间的IO操作由内核自动完成,并发送通知告知用户线程IO操作已经完成。也就是说,在异步IO中,并不会对用户线程产生任何阻塞。
  • 阻塞IO:当用户线程发起一个IO请求操作,而内核要操作的数据还没就绪,则当前线程被挂起,阻塞等待结果返回。
  • 非阻塞IO:如果数据没有就绪,就会返回一个标志信息告知用户线程,当前的数据还没有就绪。当前线程在获得此次请求结果的过程中,还可以做点其他事情。

可能会有读者觉得,怎么同步IO、异步IO和阻塞IO、非阻塞IO的操作好相似,为什么要它们都分出来呢?笔者认为,这同步、异步和阻塞、非阻塞是从不同角度来看待问题的

同步与异步

同步与异步主要是从消息通知的角度来说的。

同步就是当一个任务A的完成需要依赖另一个任务B时,只有等到B任务完成后,A才能成功地进行,这是一种可靠的任务队列。要么都成功,要么都失败,两个任务的状态可以保持一致。

异步是不需要等待任务B完成,只是通知任务B要完成什么工作,任务A也立即执行,只要任务A自己执行完了那么整个任务就算完成了。至于任务B最终是否真正完成,A任务无法确定,所以这是不可靠的一种任务队列

举个栗子,假如小J要去银行柜台办事,拿号排队。如果他只盯着号码提示牌,还时不时问是否到他了,这就是同步;如果他拿了号之后就去打电话了,等到排到他的时候柜员通知他去办理业务,这就是异步。他们之间的区别就在于,等待消息通知的方式不同。

阻塞与非阻塞

阻塞与非阻塞主要是从等待消息通知时的状态角度来说的。

阻塞就是指在调用结果返回之前,当前线程会被挂起,一直处于等待消息通知的状态,不能执行其他业务。只有当调用结果返回之后才能进行其他操作。

非阻塞与阻塞的概念相对应,就是指不能立即得到结果之前,该函数不会阻塞当前线程,而是会立即返回。虽然非阻塞的方式看上去可以明显提高CPU的利用率,但是也会使系统的线程切换增加,需要好好评估增加的CPU执行时间能不能步长系统的切换成本。

我们继续用上面的栗子,小J无论是在排队还是拿号等通知,如果在这个等待的过程中,小J除了等待消息通知之外就做不了其他的事情,那么该机制就是阻塞的。如果他可以一边打电话一边等待,这个状态就是非阻塞的。

同步、异步与阻塞、非阻塞

其实可能会有其他读者把同步与阻塞等同起来,实际上这两个是不同的。对于同步来说,很多时候当前线程还是在激活状态,只是逻辑上当前函数没有返回而已,此时,线程也会去处理其他的消息。也就是说,同步、阻塞其实是在消息通知机制下从不同角度对当前线程状态的描述

5.1 同步阻塞形式

这是效率最低的一种方式,拿上面的栗子来说,就是小J心无旁骛地排队,什么别的事都不做

在这里,同步与阻塞体现在:

  • 同步:小J等待队伍排到他办理业务;
  • 阻塞:小J在等待队伍排到他的过程中,不做其他任务处理。

5.2 异步阻塞形式

如果小J在银行等待办理业务的时候,领了号,这时候就采用了异步的方式去等待消息被触发(通知),等着柜员喊他的号而不是时刻盯着是不是排到他了。但是在这段时间里,他还是不能离开银行去做其他的事情,那么很显然,他被阻塞在这个等待喊号的操作上了。

在这里,异步与阻塞体现在:

  • 异步:排到小J的话柜员会喊他的号码;
  • 阻塞:等待喊号的过程中,不能做其他事情。

5.3 同步非阻塞形式

实际上效率也是低下。小J在排队的过程中可以打电话,但是要边打电话边看看还有多久才排到他。如果将打电话和观察排队情况看成是程序中的两个操作的话,这个程序需要在这两个不同的行为之间来回切换。

在这里,同步与非阻塞体现在:

  • 同步:排队等待轮到他办理业务;
  • 非阻塞:可以在排队的过程中打电话,只不过要时不时看看还要多久才排到他办理业务。

5.4 异步非阻塞形式

这是一个效率更高的模式。小J在拿号之后可以去打电话,只要等待柜员喊号就可以了,在这里打电话是等待着的事情,而通知小J办理业务是柜员的事情。

在这里,异步和非阻塞体现在:

  • 异步:柜员喊小J去办理业务;
  • 非阻塞:在等待喊号的过程中,小J去打电话,只要接收到柜员喊号的通知即可,无需关注是否队伍的进度。

也就是说,同步和异步仅需关注消息如何通知的机制,而阻塞和非阻塞关注的是在等待消息通知的过程中能不能去做别的事。在同步情况下,是由处理者自己去等待消息是否被触发,而异步情况下是由触发机制来通知处理者处理业务。

Linux的五种IO模型

在我们了解Linux操作系统的IO操作,以及同步与异步、阻塞与非阻塞的概念之后,我们来看看Linux系统中根据同步、异步、阻塞、非阻塞实现的五种IO模型。以Linux下的系统调用recv为例,是一个用于从套接字上接收一个消息,因为是系统调用,所以在调用的时候,会从用户空间切换到内核空间运行一段时间后,再切换回来。在默认情况下recv会等到网络数据到达并复制到用户空间或发生错误时返回。

6.1 同步阻塞IO模型

从系统调用recv到将数据从内核复制到用户空间并返回,在这段时间内进程始终阻塞。就相当于,小J想去柜台办理业务,如果柜台业务繁忙,他也要排队,直到排到他办理完业务,才能去做别的事。显然,这个IO模型是同步且阻塞的。

?6.2 同步非阻塞IO模型

在这里recv不管有没有获得到数据都返回,如果没有数据的话就过段时间再调用recv看看,如此循环。就像是小J来柜台办理业务,发现柜员休息,他离开了,过一会又过来看看营业了没,直到终于碰到柜员营业了,这才办理了业务。而小J在中间离开的时间,可以做他自己的事情。但是这个模型只有在检查无数据的时候是非阻塞的,在数据到达的时候依然要等待复制数据到用户空间(办理业务),因此它还是同步IO。

6.3 IO复用模型

在IO复用模型中,调用recv之前会先调用select或poll,这两个系统调用都可以在内核准备好数据(网络数据已经到达内核了)时告知用户进程,它准备好了,这时候再调用recv时是一定有数据的。因此在这一模型中,进程阻塞于select或poll,而没有阻塞在recv上。就相当于,小J来银行办理业务,大堂经理告诉他现在所有柜台都有人在办理业务,等有空位再告诉他。于是小J就等啊等(select或poll调用中),过了一会儿大堂经理告诉他有柜台空出来可以办理业务了,但是具体是几号柜台,你自己找下吧,于是小J就只能挨个柜台地找。

6.4 信号驱动IO模型

此处会通过调用sigaction注册信号函数,在内核数据准备好的时候系统就中断当前程序,执行信号函数(在这里调用recv)。相当于,小J让大堂经理在柜台有空位的时候通知他(注册信号函数),等没多久大堂经理通知他,因为他是银行的VIPPP会员,所以专门给他开了一个柜台来办理业务,小J就去特席柜台办理业务了。但即使在等待的过程中是非阻塞的,但在办理业务的过程中依然是同步的。

6.5 异步IO模型

调用aio_read令内核把数据准备好,并且复制到用户进程空间后执行事先指定好的函数。就像是,小J交代大堂经理把业务给办理好了就通知他来验收,在这个过程中小J可以去做自己的事情。这就是真正的异步IO。

我们可以看到,前四种模型都是属于同步IO,因为在内核数据复制到用户空间的这一过程都是阻塞的。而最后一种异步IO,通过将IO操作交给操作系统处理,当前进程不关心具体IO的实现,后来再通过回调函数,或信号量通知当前进程直接对IO返回结果进行处理。

BIO、NIO、AIO的区别

上文谈到IO的四种模式:同步阻塞IO、同步非阻塞IO、异步阻塞IO、异步非阻塞IO,在JavaIO中提供了三种模式的实现:BIO(同步阻塞IO)、NIO(同步非阻塞IO)、AIO(异步非阻塞IO)。至于这四种模式之间的区别,上文已经有较为详细的介绍了,接下来笔者将对这三种JavaIO类型之间的区别进行介绍。

  • BIO:同步并阻塞,在服务器中实现的模式为一个连接一个线程。也就是说,客户端有连接请求的时候,服务器就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然这也可以通过线程池机制改善。BIO一般适用于连接数目小且固定的架构,这种方式对于服务器资源要求比较高,而且并发局限于应用中,是JDK1.4之前的唯一选择,但好在程序直观简单,易理解。
  • NIO:同步并非阻塞,在服务器中实现的模式为一个请求一个线程,也就是说,客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到有连接IO请求时才会启动一个线程进行处理。NIO一般适用于连接数目多且连接比较短(轻操作)的架构,并发局限于应用中,编程比较复杂,从JDK1.4开始支持。
  • AIO:异步并非阻塞,在服务器中实现的模式为一个有效请求一个线程,也就是说,客户端的IO请求都是通过操作系统先完成之后,再通知服务器应用去启动线程进行处理。AIO一般适用于连接数目多且连接比较长(重操作)的架构,充分调用操作系统参与并发操作,编程比较复杂,从JDK1.7开始支持。

结语

本文从操作系统进行文件读写入手,对同步、异步、阻塞、非阻塞以及它们组合而成的IO模式进行了介绍,还了解Linux操作系统中的五种IO模型,以及重新回到JavaIO,看待BIO、NIO、AIO之间的区别。

如果本文对你有帮助,请给一个赞吧,这会是我最大的动力~

相关推荐

PHPMailer远程命令执行漏洞分析

摘要:PHPMailer是一个强大的PHP编写的邮件发送类,但近日被爆出远程命令执行漏洞,该漏洞实际上是什么,有何种影响,本文对该漏洞进行了分析及验证方法,并给出防护方案。0x00漏洞概要PHPMa...

「安全漏洞」DedeCMS-5.8.1 SSTI模板注入导致RCE

漏洞类型SSTIRCE利用条件影响范围应用漏洞概述2021年9月30日,国外安全研究人员StevenSeeley披露了最新的DedeCMS版本中存在的一处SQL注入漏洞以及一处SSTI导致的RCE...

回顾使用PHP原生发送电子邮件(终)文件附件

FileAttachments文件附件Fileattachmentsworkjustlikemixedemail,exceptthatadifferentcontenttyp...

php-fpm.conf & php.ini 安全优化实践

0x01关于php其历史相对已经比较久远了,这里也就不废话了,属弱类型中一种解释型语言除了web开发以及写些简单的exp,暂未发现其它牛逼用途,暂以中小型web站点开发为主另外,低版本的php自身...

linux 安全配置 ossec 开源检测

linux安全配置ossec开源检测一:介绍主要功能有日志分析、完整性检查、rootkit检测、基于时间的警报和主动响应。除了具有入侵检测系统功能外,它还一般被用在SEM/SIM(安全事件管理(...

PHP使用PHPMailer发送验证码邮件的方法与调用逻辑

首先我们需要下载PHPMailer:https://github.com/PHPMailer/PHPMailer一般情况下我们只需要压缩包中的src文件夹中的文件,并保存至根目录即可:设置一个文件,如...

回顾使用PHP原生发送电子邮件(一)

IwishIcouldremembertheveryfirstemailmessageIeversent.Unfortunately,thetruthisthatI...

PHPMAILER实现PHP发邮件功能php实例

这篇文章主要为大家详细介绍了PHPMAILER实现PHP发邮件功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下本文实例为大家分享了PHPMAILER实现PHP发邮件功能的具体代码,供大家参考,具...

500道网络安全面试题集锦(附答案)

本篇文章内容为网络安全各个方向涉及的面试题,星数越多代表问题出现的几率越大,但是无论如何都无法覆盖所有的面试问题,更多的还是希望由点达面,查漏补缺,然后祝各位前程似锦,都能找到自己满意的工作!一、We...

网站放家里,随处看电影「Apache+php+ssl 安装和配置」

  使用5G网络,随处都可以看到放自己家里电脑的视频。这个功能很容易实现,不需要太多的专业知识,也不需要额外花钱。如果确实需要,最多花不到两百块钱买一台旧电脑放家里,做个网站,就能解决全部问题,Fre...

Windows2008中 Magic Winmail Server提权

MagicWinmailServer是安全易用全功能的邮件服务器软件,不仅支持SMTP/POP3/IMAP/Webmail/LDAP(公共地址簿)/多域/发信认证/反垃圾邮件/邮件过滤/邮件组...

利用PHPmailer发送邮件

早上帮朋友做一个收集客户联系方式的页面,要求能实时推送信息给管理员。刚开始想到做后台管理,因为时间紧,做后台是赶不上了。想过通过短信发送,成本太高,否决了。。。灵机一动,客户提交时直接把信息发送到邮箱...

phpmailer发送邮件

phpmailer发送邮件PHP内置的mail函数使用起来不够方便,另外受其他语言的影响,博主更偏好面向对象的包管理模式,因此phpmailer成为了我用PHP发送邮件的首选,这里分享给大家。库导入这...

PHP初级教程:读取输入

PHP读取输入:Form:?formaction="welcome.php"method="post">Name:(inputtype="text...

php filter 验证Email,Url,Ip格式

今天发现一个非常好用的函数东西,filter过滤器,用于验证和过滤来自非安全来源的数据,比如用户的输入。验证Email:$email='1234567@qq.com';if(!filter_v...

取消回复欢迎 发表评论: