众所周知,在传统网络IO编程中应用程序会调用read/write系统调用进行读写操作。
read/write系统调用读写数据的具体过程?
read系统调用读取数据的过程
read系统调用结果:内核缓冲区数据拷贝到用户缓冲区。
详细说明:
-
应用程序执行read系统调用,用户态切换到内核态
-
内核检查内核缓冲区有无数据可读
- 若无,即缓冲区空了,则等待数据从网络中到达(会阻塞);当数据从网络中到达时,数据会拷贝到内核缓冲区
-
内核缓冲区有数据可读,CPU会将内核缓冲区数据拷贝到用户缓冲区中
是CPU拷贝,CPU负责“数据搬运”
-
数据拷贝完毕,则read系统调用返回,内核态切换到用户态
write系统调用写入数据的过程
write系统调用结果:用户缓冲区数据拷贝到内核缓冲区。
说明:
-
应用程序执行write系统调用,用户态切换到内核态
-
内核检查内核缓冲区是否有空间可写
- 若不可写,即缓冲区满了,则等待网卡将缓冲区中数据发送出去,此时会阻塞直到缓冲区有空间可写
-
内核缓存区有空间可写,则CPU将用户空间数据拷贝到内核空间
CPU拷贝,CPU负责“数据搬运”
-
若用户空间数据拷贝完毕(即全部拷贝到内核空间),则write系统调用返回,内核态切换到用户态
为什么read/write系统调用会阻塞?
为什么read读会阻塞
因为读的时候是从内核缓冲区读取数据的,当内核缓冲区空了就没数据可读,此时会阻塞直到内核缓冲区又有数据可读。
为什么write写会阻塞
因为写的时候是将用户缓冲区数据拷贝到内核缓冲区,即向内核缓冲区写,当内核缓冲区满了就无空间可写了,此时会阻塞直到内核缓冲区腾出空间可写。
总结
关键:
-
读写都有缓冲区,读写本质上是个生产者消费者模式
-
读时:
- 网卡是生产者,产生数据到内核缓冲区
- 应用程序是消费者,将内核缓冲区数据拷贝到用户缓冲区
应用程序消费速度快(因为内存拷贝数据速度快),当缓冲区空了就不可消费导致阻塞
-
写时:
- 应用程序是生产者,将数据从用户缓冲区拷贝到内核缓冲区
- 网卡是消费者,消费内核缓冲区数据、发送到网络中
应用程序生产速度快(因为内存拷贝数据速度快),当内核缓冲区满了就不可生产导致阻塞
-