Linux network I/O

1 缓存 I/O (Buffered I/O)介绍

对于传统的操作系统来说,普通的 I/O 操作一般会被内核缓存,这种 I/O 被称作缓存 I/O。缓存 I/O 又被称作标准 I/O,大多数文件系统的默认 I/O 操作都是缓存 I/O。在 Linux 的缓存 I/O 机制中,操作系统会将 I/O 的数据缓存在文件系统的页缓存( page cache )中,也就是说,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间

(1) 对于读操作来说,当应用程序尝试读取某块数据的时候,如果这块数据已经存放在了页缓存中,那么这块数据就可以立即返回给应用程序,而不需要经过实际的物理读盘操作。当然,如果数据在应用程序读取之前并未被存放在页缓存中,那么就需要先将数据从磁盘读到页缓存中去。一个典型的读取磁盘中数据的流程图如下所示: 

(2) 对于写操作来说,应用程序也会将数据先写到页缓存中去,数据是否被立即写到磁盘上去取决于应用程序所采用的写操作机制:如果用户采用的是同步写机制( synchronous writes ), 那么数据会立即被写回到磁盘上,应用程序会一直等到数据被写完为止;如果用户采用的是延迟写机制( deferred writes ),那么应用程序就完全不需要等到数据全部被写回到磁盘,数据只要被写到页缓存中去就可以了。在延迟写机制的情况下,操作系统会定期地将放在页缓存中的数据刷到磁盘上。与异步写机制( asynchronous writes )不同的是,延迟写机制在数据完全写到磁盘上的时候不会通知应用程序,而异步写机制在数据完全写到磁盘上的时候是会返回给应用程序的。所以延迟写机制本身是存在数据丢失的风险的,而异步写机制则不会有这方面的担心。

缓存 I/O 优点:

  • 缓存 I/O 使用了操作系统内核缓冲区,在一定程度上分离了应用程序空间和实际的物理设备。缓存 I/O 可以减少读盘的次数,从而提高性能。

缓存I/O缺点:

  • 在缓存 I/O 机制中,DMA 方式可以将数据直接从磁盘读到页缓存中,或者将数据从页缓存直接写回到磁盘上,而不能直接在应用程序地址空间和磁盘之间进行数据传输,这样的话,数据在传输过程中需要在应用程序地址空间和页缓存之间进行多次数据拷贝操作,这些数据拷贝操作所带来的 CPU 以及内存开销是非常大的。对于某些特殊的应用程序来说,避开操作系统内核缓冲区而直接在应用程序地址空间和磁盘之间传输数据会比使用操作系统内核缓冲区获取更好的性能。

2 Linux环境下的network I/O

网络IO的本质就是socket的读取,socket在linux系统被抽象为流,IO可以理解为对流的操作。文章开始的时候也提到了,对于一次IO访问(以read为例),数据会先被拷贝到操作系统内核的缓冲区,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间中。

所以说,当一个read操作发生时,它会经历两个阶段:

第一个阶段:等待数据准备。

第二个阶段:将数据从内核拷贝到进程中

对于socket流而言:

第一步:通常涉及等待网络上的数据分组到达,然后复制到内核的某个缓冲区。

第二步:把数据从内核缓冲区复制到应用进程缓冲区。

Linux环境下的五种IO Modle: blocking IO, nonblocking IO, IO multiplexing, signal driven IO, asynchronous IO. 其中前四种比较常见。

(1) blocking IO

在阻塞IO模型中,从调用系统函数获取数据开始到得到数据,当前的进程或者线程始终是处于阻塞状态的,也就是什么都不干,直到等完数据准备好和将数据搬迁到用户空间为止:

1) 用户首先发出系统调用函数希望获取数据;

2) 系统调用会进入内核检查是否有数据准备完毕,如果没有就一直等待;

3) 当数据准备完毕的时候会将数据拷贝到用户空间;

4) 拷贝完毕返回一个获取数据成功的返回值来告诉用户可以进行数据的处理了;在此期间,用户进程或者线程一直是处于阻塞状态的,无论是等待数据还是进行数据的拷贝;

(2) nonblocking IO

和阻塞式的IO模型不同,当发出了系统调用的时候,如果这时候数据还没有准备好,进程或线程并不会进入阻塞模式一直等待,而是会反复轮询“数据好没…数据好没…数据好没…”,这是比较耗CPU资源的,而当数据准备好之后会和阻塞IO模型一样进行数据的拷贝:

1) 首先用户发出系统调用,去向内核申请获取想要的数据;

2) 内核检查发现数据还没准备好,就会返回一个错误值;

3) 用户接收到错误值并不甘心,就会反复反复询问内核是否有数据准备好;

4) 内核一直检查直到有数据准备完毕,进行数据的搬迁,这时用户会进入阻塞等待状态等待数据拷贝完毕;

5) 数据提取到用户空间之后会返回一个成功状态通知用户数据完毕,这时用户就可以进行数据的处理了;

(3) IO multiplexing

既然是复用,说明一次性可以管理或处理多个IO,主要是靠select函数或者poll(epoll)函数来完成;这些函数同样会阻塞进程,但是和阻塞式IO不同的是IO复用模型可以一次性阻塞多个IO操作。同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。

1) 用户首先调用select或者poll函数对多个IO接口操作进行检测,同时会使进程或者线程阻塞;

2) 当有至少一个IO接口响应的时候,系统就会通知内核调用相应的函数来获取数据;

3) 这时内核将数据拷贝迁移至内核空间,进程或者线程仍然处于阻塞状态;

4) 数据就绪,返回一个成功值告诉用户可以处理数据了;

(4) signal driven IO

用户首先注册一个处理IO信号的信号处理函数,当数据还没准备好的时候进程或者线程并不阻塞,当数据准备好的时候用户进程或者线程会收到一个信号SIGIO,这时候就会调用信号处理函数,在信号处理函数中调用IO函数操作数据,完成之后通知用户:

1) 用户程序中事先注册好一个对于SIGIO的信号处理函数;

2) 当数据准备完毕的时候会向用户进程或者线程发送一个SIGIO信号,这时信号就会被捕捉;

3) 捕捉信号之后就会执行用户自定义的一个信号处理函数,并且在函数中调用系统函数去获取数据;

4) 获取数据同样会将数据进行拷贝到用户空间,这时进程或者线程仍然会被阻塞;

5) 当数据准备完毕同样会通知用户,之后就可以进行数据的处理了;

(5) asynchronous IO

对于异步的IO模型来说,数据的等待和搬迁都不由当前的进程或者线程来处理,调用相应系统函数之后就会直接返回继续执行,因此当前用户程并不会被阻塞,当数据已经在用户空间准备就绪之后会以状态、通知或者回调来告诉用户可以进行数据的处理了:

1) 用户程序调用aio_read函数,告诉内核描述字、缓冲区指针、缓冲区大小、文件偏移以及通知的方式,之后便立即返回;

2) 这时内核相应的数据操作组件会进行数据的等待和搬迁,期间用户程序并不受影响继续执行;

3) 当数据都已经在用户空间准备就绪之后就会通过在函数中预留的通知方式来通知用户程序处理数据;

总结:

从上面的分析中不难发现,在对于数据的获取过程中都是进行了两个主要的部分:数据的等待和数据的搬迁;除此相同点之外,下面就总结一下各种IO模型的区别: 

从上面的比较可以发现:前四种IO模型也就是阻塞IO、非阻塞IO、IO复用和信号驱动IO模型都是同步的,只有最后一种是异步的异步IO模型;默认情况下所创建出来的socket都是以阻塞的形式,比如网络通信中的recvfrom和sendto,或者read和write等函数都是以阻塞的方式来实现的。

参考: 
Linux 中直接 I/O 机制的介绍 
Linux之——五种IO模型

IO - 同步,异步,阻塞,非阻塞

时间: 2024-08-10 02:05:46

Linux network I/O的相关文章

Netruon 理解(12):使用 Linux bridge 将 Linux network namespace 连接外网

学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GRE/VxLAN 虚拟网络 (4)Neutron OVS OpenFlow 流表 和 L2 Population (5)Neutron DHCP Agent (6)Neutron L3 Agent (7)Neutron LBaas (8)Neutron Security Group (9)Neutro

Linux network namespaces

介绍OpenStack neutron使用Linux网络命名空间来避免物理网络和虚拟网络间的冲突,或者不同虚拟网络间的冲突. 网络命名空间就是一个独立的网络协议栈,它有自己的网络接口,路由,以及防火墙规则. 网络命名空间通常是位于目录/var/run/netns/下的文件描述符. 例如,使用ip netns add命令创建一个命名空间: ip netns add bule 查看目录/var/run/netns/: $ ls /var/run/netns/ blue 网络命名空间常用于虚拟化中.因

Linux Network IO Model Learning

目录 0. 引言 1. IO机制简介 2. 阻塞式IO模型(blocking IO model) 3. 非阻塞式IO模型(noblocking IO model) 4. IO复用式IO模型(IO multiplexing model) 5. 信号驱动式IO模型(signal-driven IO model) 6. 异步IO式IO模型(asynchronous IO model) 7. Linux下IO技术简介 8. IO模型编程举例 0. 引言 Linux将所有外部设备都看做一个文件来进行操作.

Netruon 理解(11):使用 NAT 将 Linux network namespace 连接外网

学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GRE/VxLAN 虚拟网络 (4)Neutron OVS OpenFlow 流表 和 L2 Population (5)Neutron DHCP Agent (6)Neutron L3 Agent (7)Neutron LBaas (8)Neutron Security Group (9)Neutro

【learning log】Linux network programming

DNS host entry 包含 DNS database 中有关某一 domin name 或 ip address 的 DNS 信息. 1 struct hostent{ 2 char *h_name; 3 char *h_aliases; 4 int h_addrtype; 5 int h_length; 6 char **h_addr_list; 7 }; hostinfo 程序, 用来从 ip 或 domin name 解析 DNS info. 1 /*This program is

linux network namespace

linux network namespace在OpenStack和docker中都经常遇到,这次好好记录下使用方法,以备查询. 1.创建一个net namespace ip netns add blue 2.查看net namespace ip netns list 3.创建端口对 ip link add veth0 type veth peer name veth1 4.查看端口对 ip link <list> 5.增加端口到namespace ip link set veth1 netn

linux network code

sk_buff: socket buffertstamp: buffer, 到达主机,离开主机的时间sk: 对应的socket句柄, 到network layer.dev:从哪个设备流入或流出.skb: queued ATM(Asynchronous Transfer Mode).cb: Control buffer,48个字节供各层自由使用._skb_refdst linux network code

Linux Network Bridge

1. About Network Bridge A network bridge is a Link Layer device which forwards traffic between networks based on MAC addresses and is therefore also referred to as a Layer 2 device. It makes forwarding decisions based on tables of MAC addresses which

Linux Network Management

Linux网络管理 (YouTube视频教程) ISO/OSI七层模型 ISO: The International Organization for Standardization 国际标准化组织 OSI: Open Systems Interconnection model 开放系统互连模型 MAC地址负责局域网通信,IP地址负责外网通信 文件传输端口(FTP端口)默认21 Www网页端口默认80 Mail邮件默认端口是25和110 ISO/OSI七层模型是理论基础,TCP/IP四层模型是优

Linux Network Related Drive

catalog 1. 通过套接字通信 2. 网络实现的分层模型 3. 网络命名空间 4. 套接字缓冲区 5. 网络访问层 6. 网络层 7. 传输层 8. 应用层 9. 内核内部的网络通信 1. 通过套接字通信 Linux的设计思想是"万物皆文件",从开发者角度来看,外部设备在Linux(以及UNIX)中都是普通文件,通过正常的读写操作即可访问,但是对于网卡而言,情况会复杂的多.网卡的运作方式与普通的块设备和字符设备完全不同,一个原因是(所有层次)使用了许多不同的通信协议,为建立连接需