什么是I/O?
在计算机操作系统中,所谓的I/O就是输入(Input)和输出(Output),也可以理解为读(Read)和写(Write),针对不同的对象,I/O模式可以划分为磁盘IO模型和网络IO模型。
IO操作会涉及到用户空间和内核空间的转换,先来理解以下规则:
内存空间分为用户空间和内核空间,也称为用户缓冲区和内核缓冲区
用户的应用程序不能直接操作内核空间,需要将数据从内核空间拷贝到用户空间才能使用
无论是read操作,还是write操作,都只能在内核空间里执行
磁盘IO和网络IO请求加载到内存的数据都是先放在内核空间的
用户程序不能直接访问内核缓冲区,如果要读取数据,先检查内核缓冲区有没有对应的数据,如果有将数据拷贝到用户缓冲区,供用户使用,如果没有对应的数据,需要先进行磁盘io,将磁盘数据读取到内核缓冲区中,磁盘io这个过程不需要cpu,也不能说一点不需要,只是需要的cpu资源很少,其实是将这个io交给了一个类似小cpu的DMA控制器,这个控制器有自己的寄存器(记录主存地址和取到的字的count等).大致流程参考下面:
CPU计算文件地址 ==> 委派DMA读取文件 ==> DMA接管总线 ==> CPU的A进程阻塞,挂起 ==> CPU切换到B进程 ==> DMA读完文件后通知CPU(一个中断异常) ==> CPU切换回A进程操作文件
同步:发送一个请求,等待结果的返回,再发送下一个请求,可以避免死锁和脏读的发生。
异步:发送一个请求,不等待结果的返回,随时可以发送下一个请求,可以提高效率保证并发,
阻塞:传统的io流都是阻塞的,当一个线程调用read或write方法时,线程会进入阻塞状态,该线程不能执行其他的任务,直到数据的读取或者写入完成,在完成网络通讯进行io时,由于线程会阻塞,所以服务端必须为每一个客户端提供一个独立的线程进行处理,当服务器需要处理大量的客户端时候,性能急剧下降,
非阻塞:当线程从某个通道读取数据的时候,若没有数据可用,该线程会去执行其他的任务 ,线程通常将非阻塞io的空闲时间用于其他通道上执行io操作,所以单独的线程可以管理多个输入和输出,因此nio可以让服务器使用一个或者多个有限几个线程来同时处理连接到服务器上的所有客户端。
同步阻塞叫bio:
数据的读取和写入必须总是在一个线程内等待完成,线程等待结果的完成,期间进入阻塞,什么也不做,适用于连接数据较小,且固定的架构,对服务器的资源要求比较高,并发局限在应用中1.4以前的唯一选择。
#java.io包下的列
InputStream
outputStreamReader
writer
#网络编程
ServerSocketsocket
#阻塞:read方法accept方法阻塞式的。
同步非阻塞叫nio:可以设置阻塞或非阻塞模式,线程不停的询问结果的完成情况。适用于连接数据较多且连接比较短的架构,比如聊天服务器
#同步非阻塞java.nio包的类
Buffer
ByteBuffer
charBuffer
Channel
FileChanne1
#网络编程
ServerSocketChannel
socketChannel
Selector
#非阻塞:read方法accept方法可以设置阻塞还是非阻塞。
异步非阻塞叫aio:无需一个线程去不停询问结果是否完成,如果结果完成,系统会通知对应的线程进行处理。适用于连接数较多且连接时间较长的架构中,比如相册服务器,充分调用os参与并发操作,1.7之后开始支持
#java.nio.channels 包下网络编程
Asynchronoussocketchannel
AsynchronousserverSocketchannelAsynchronousFilechannel
AsynchronousDatagramChannel
#非阻塞: read方法 accept方法非阻塞。
网络io的流程(仅供参考):
发送流程/写流程
具体参考osi模型,大致就是将数据进行封装,通过TCP/ip协议进行传输,期间经过路由转发,到达指定的目的地址
接收流程/读流程
网卡(Network Adapter),也称网络适配器,是一个 硬件设备,有全球唯一的 MAC(Media Access Control)地址,MAC地址在网卡生产时就被烧制在ROM中,网卡初始化时恢复到计算机中。
网卡收到的数据是 光信号或电信号,然后将其还原成 数字信息(1和0组成)。根据 FCS(帧校验序列,Frame Check Sequence)校验数据,判断数据在传输过程是否因噪音等影响导致信号失真,从而导致数据错误,需要丢弃这种无效的数据包,
网卡驱动
硬件需要驱动程序来控制,就像电脑需要操作系统一样,而网卡驱动就是CPU控制和使用网卡的程序
。网卡处理完数字信号后,接下来的数据接收需要CPU参与,此时网卡通过中断将数据包达到的事件通知给CPU
。接着,CPU暂停手头工作,开始用网卡驱动来干活。
- 从网卡缓冲区读取接收到的数据
- 根据MAC头部的以太类型字段判断协议种类并调用处理该协议的软件(即协议栈)
1.网卡驱动程序提取这个帧的全部内容,去掉以太网的帧头,然后向上传递给IP层
2.IP层接收到包已经,继续去掉IP头的内容,然后交给TCP层
3.TCP层根据TCP协议定义的格式,继续解包,read()从socket buffer读取数据,然后传递给应用层
4.应用层根据TCP层传来的数据,按照对应的应用层来分析包。应用程序通过read()从socket buffer读取数据。