前言
依稀记得当年大学上课的时候,老师说IO这块考试不考,感兴趣的同学可以自行了解。。。一直被蒙在鼓里,直到校招的时候被面试官一套连招问麻了。。。
现如今鄙人已成为一名练习时长两年半的Java练习生,怎么能不了解网络IO背后的细节呢。本篇揭开一波网络IO的神秘面纱
什么是IO
字面意思,input/output输入输出,linux世界中一切皆文件,而文件就是一串二进制流,不管Socket、FIFO、管道还是终端,对我们来说,一切都是二进制流。
- 在信息的交换过程中只是对这些流进行数据做接收转发,简称为I/O操作。
- 往流中读取数据,系统调用Read,写入数据,系统调用Write。
- 通常一个完整的IO包含两个步骤,磁盘IO和网络IO
磁盘IO
网络IO
- 完整的IO流程为:
- 磁盘IO负责把磁盘的数据从磁盘经过内核空间加载到用户空间
- 网络IO负责数据经过用户空间调用内核空间的api发送到网卡
用户空间与内核空间
- 操作系统为了支持多个应用同时运行,需要保证不同进程之间相对独立(一个进程的崩溃不会影响其他的进程,恶意进程不能直接读取和修改其他进程运行时的代码和数据)。用户程序不能影响系统调度,因此操作系统内核需要拥有高于普通进程的权限, 以此来调度和管理用户的应用程序。
- 于是内存空间被划分为两部分,内核空间存储的代码和数据具有更高级别的权限。内存访问的相关硬件在程序执行期间会进行访问控制,使得用户空间的程序不能直接读写内核空间的内存。
IO的阶段
- 硬件接口加载数据到内核空间
- 内核空间拷贝数据到用户空间
- 用户空间无法直接操作底层api,对数据进行加载、拷贝至网卡的操作需要切换成内核空间调用对应api完成
零拷贝
一切流行的组件为了追求速度都做了一些零拷贝的优化,先说一下传统拷贝。
传统拷贝
- 传统的文件传输方式会经历4次数据拷贝
- 硬件DMA拷贝到内核空间的内核缓冲区中
- 内核空间的内缓冲区CPU拷贝到用户空间的用户缓冲区
- 数据经过处理后从用户空间的用户缓冲区CPU拷贝到内核空间的内核缓冲区
- 从内核缓冲区DMA拷贝到网卡设备
mmp + write 零拷贝
- mmp使用虚拟内存,把内核空间和用户空间的虚拟地址映射在同一个物理地址从而减少数据拷贝次数
- mmap是将读缓冲区的地址和用户缓冲区的地址进行映射,内核缓冲区和应用缓冲区共享,所以节省了一次CPU拷贝,并且用户进程内存是虚拟的,只是映射到内核的读缓冲区,可以节省一半的内存空
sendfile 零拷贝
- sendfile表示在两个文件描述符之间传输数据,它是在操作系统内核中操作的,避免了数据从内核缓冲区和用户缓冲区之间的拷贝操作,因此可以使用它来实现零拷贝。