网络编程之I/O模型

声明:转载需注明出处,个人主页:supiccc

I/O 复用是什么

内核一旦发现进程指定的一个或多个I/O条件就绪,就通知进程。

为什么需要 I/O 复用

  • 客户需要处理多个描述字时;
  • 一个客户需要同时处理多个套接口时;
  • TCP 同时处理监听套接口和已连接套接口时;
  • 服务器既要处理 TCP 又要处理 UDP 时;
  • 一个服务器需要处理多个服务或多个协议时;

开始前须知

一个输入操作分为两个阶段:一个是等待数据准备的阶段,一个是从内核拷贝数据到进程的阶段。

五种 I/O 模型

阻塞 I/O(常用)模型

若一个进程调用 recvfrom( ) 来读取数据,进程从调用 recvfrom (系统调用)开始到它返回的整段时间内是阻塞的,只有成功返回后进程才能开始处理数据。

非阻塞 I/O 模型

进程调用 recvfrom 时若无数据报准备好,内核立即返回一个 EWOULDBLOCK 错误,应用进程会不停的调用 recvfrom,此过程称为轮询(polling),这么做往往需要耗费大量CPU时间,通常是在专门提供某种功能的系统中才有。

I/O 复用模型

进程调用 select(poll),然后阻塞在这两个系统调用的某一个上。

比如使用 select(poll) 和 recvfrom 时,当 select 返回套接口可读这一条件时,才调用 recvfrom 把所读数据拷贝到进程缓冲区。

优势在于可以等待多个描述字就绪。类似于多线程中使用阻塞 I/O。

信号驱动 I/O 模型

使用信号让内核在描述字就绪时发送 SICIO 信号通知进程。

异步 I/O 模型

进程告知内核启动某个操作,随即返回,由内核进行整个操作,操作完成后通知进程! (POSIX 异步 I/O 函数以 aio_ 或 lio_ 开头),不阻塞!

比较

前四种模型主要区别在第一阶段(等待数据准备),第二阶段都会阻塞在读取过程,半阻塞。

所以前四种模型被称为同步 I/O 模型,其真正的I/O 操作将阻塞进程!

I/O 复用:select 函数和 poll 函数

允许进程指示内核等待多个事件中的任何一个发送,并仅在有一个或多个事件发生或经历一段指定的时间才可以唤醒它!

#include 
#include 
int select(int maxfdp1, fd_set * readset, fd_set * writeset,
    fd_set * exceptset, const struct timeval * timeout);
                                返回:就绪描述字的正数目,0-超时,-1-出错
复制代码
#include 
int poll(struct pollfd * fdarra, unsigned long nfds, int timeout);
                                返回:就绪描述字的正数目,0-超时,-1-出错
复制代码

参考资料

UNIX 网络编程第 1 卷 :套接口 API (第三版)

你可能感兴趣的:(网络编程之I/O模型)