网络I/O模型

本文介绍了网络I/O的四种模型:阻塞IO、非阻塞IO、多路IO复用和异步IO。在阻塞IO中,进程在等待数据和拷贝数据时都会被阻塞。非阻塞IO则不会阻塞,函数会立即返回。多路IO复用通过select函数轮询socket,当数据准备好时通知用户进程。异步IO模型在操作完成前就返回,拷贝完成后发送信号。这些模型在处理网络通信时各有优劣,适用于不同的场景。
摘要由CSDN通过智能技术生成

I/O 有两种操作,同步 IO 和异步 IO 。 同步 IO 指的是,必须等待 IO 操作完成后,控制权才返回给用户进程异步 IO 指的是,无须等待 IO 操作完成,就将控制权返回给用户进程。

网络中的 IO ,由于不同的 IO 设备有着不同的特点,网络通信中往往需要等待 。 常见的有以下 4 种情况 。
( 1 )输入操作 : 等待数据到达套接字接收缓冲区
( 2 )输出操作 : 等待套接字发送缓冲区有足够的空间容纳将要发送的数据。
( 3 )服务器接收连接请求:等待新的客户端连接请求的到来 。
( 4 )客户端发送连接请求 : 等待服务器回送客户的发起的 SYN 所对应的 ACK 。

当一个网络 IO (假设是 read)发生时,它会涉及两个系统对象, 一个是调用这个 IO 的进程,另 一个是系统内核。 当一个 read 操作发生时,它会经历两个阶段:①等待数据准备;②将数据从内核拷贝到进程中

4 种网络 IO 模型: ①阻塞 IO 模型;②非阻塞 IO 模型;③多路 IO 复用模型;④异步 IO 模型

1. 阻塞IO模型

在 Linux 中,默认情况下所有的 socket 都是阻塞的 , 一个典型的读操作流程如图所示 。

在这里插入图片描述

阻塞和非阻塞的概念描述的是用户线程调用内核 IO 操作的方式:阻塞是指 IO 操作需要彻底完成后才返回到用户空间;而非阻塞是指 IO 操作被调用后立即返回给用户一个状态值,不需要等到 IO 操作彻底完成。

当应用进程调用了 recvfrom 这个系统调用后,系统内核就开始了 IO 的第一个阶段 :准备数据。 对于网络 IO 来说,很多时候数据在一开始还没到达时(比如还没有收到一个完整的TCP 包),系统内核就要等待足够的数据到来 。 而在用户进程这边,整个进程会被阻塞 。 当系统内核一直等到数据准备好了,它就会将数据从系统内核中拷贝到用户内存中,然后系统内核返回结果,用户进程才解除阻塞的状态,重新运行起来 。 所以,阻塞 IO 模型的特点就是在 IO 执行的两个阶段(等待数据和拷贝数据)都被阻塞了

大部分的 socket 接口都是阻塞型的 。 所谓阻塞型接口是指系统调用时(一般是 IO 接口)却不返回调用结果,并让当前线程一直处于阻塞状态 只有当该系统调用获得结果或者超时出错时才返回结果。 实际上,除非特别指定, 几乎所有的 IO 接口(包括 socket 接口)都是阻塞型的 。 这给网络编程带来了一个很大的问题,如在调用 send()的同时,线程处于阻塞状态,则在此期间,线程将无法执行任何运算或响应任何网络请求

一个简单的改进方案是在服务器端使用多线程(或多进程) 。 多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),这样任何一个连接的阻塞都不会影响其他的连接。一般使用多线程,多线程开销远小于多进程(如果单个服务执行体需要消耗较多的 CPU 资源,例如需要进行大规模或长时间的数据运算或文件访问,则推荐使用较为安全的进程 )

一个 socket 可以 accept 多次。让 accept()能够返回一个新的 socket。(让服务器同时为多个客户端提供一问一答的服务 。)

int accept(int fd, struct sockaddr *addr , socklen_t *addrlen) ;

输入参数fd是从 socket()、 bind()和 listen()中沿用下来的 socket 句柄值。 执行完 bind()和 listen()后,操作系统已经开始在指定的端口处监听所有的连接请求,如果有请求,则将该连接请求加入请求队列 。 调用 accept()接口正是从 socket fd 的请求队列抽取第一个连接信息,创建一个与fd同类的新的 socket 返回句柄这个新的 socket 句柄即是后续 read()和recv()的输入参数 。 如果请求队列当前没有请求,则 accept()将进入阻塞状态直到有请求进入队列 。

2. 非阻塞IO模型(socket不阻塞,函数立即返回:字节数、0、-1)

在Linux 下,可以通过设置socket 使IO 变为非阻塞状态
在这里插入图片描述
在这里插入图片描述
使用如下的函数可以将某句柄归设为非阻塞状态:

fcntl( fd , F_SETFL , O_NONBLOCK );

在这里插入图片描述

3. 多路IO复用模型(select阻塞,但socket的io不阻塞)

多路IO 复用,有时也称为事件驱动IO 。它的基本原理就是有个函数(如 select )会不断地轮询所负责的所有socket ,当某个socket 有数据到达了,就通知用户进程,

在这里插入图片描述

当用户进程调用了select ,那么整个进程会被阻塞,而同时,内核会“监视”所有select负责的socket ,当任何一个soc ket 中的数据准备好了, select 就会返回。这个时候用户进程再调用read 操作,将数据从内核拷贝到用户进程。

在这里插入图片描述

FD_ ZERO(int fd, fd_set * fds) ;
FD_ SET(int fd, fd_set * fds) ;
FD_ISSET (工nt fd , fd_ set * fds) ;
FD_CLR(int fd, fd_set* fds) ;
int select(int nfds , fd_set * readfds , fd_set *writefds, fd_set *exceptfds , struct timeval * timeout);

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

优缺点

在这里插入图片描述
在这里插入图片描述

4. 异步 IO 模型(无论成功与否,函数立即返回;拷贝完成后会发送一个信号)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值