栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

第2章 高性能网络设计 - I/O多路复用

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

第2章 高性能网络设计 - I/O多路复用

第2章 高性能网络设计 2.1 I/O多路复用

重点内容

  • 网络 I/O 模型、I/O 多路复用(select、poll、epoll)
  • reactor 的原理与实现
  • http/https 服务器的实现
  • websocket 协议与服务器实现
2.1.1 网络 I/O 模型与 I/O 多路复用

Unix 有五种 I/O 模型:阻塞 I/O 模型(blocking I/O model)、非阻塞 I/O 模型(non-blocking model)、多路复用 I/O 模型(I/O multiplexing model)、信号驱动式 I/O 模型(signal blocking I/O model)、异步 I/O 模型(asynchronous I/O model)

阻塞与非阻塞的概念

阻塞:阻塞调用是指调用的 I/O 函数没有完成相关的功能,在调用结果返回之前,当前进程被挂起。函数只有在得到结果之后才会返回。

阻塞型 I/O 模型一般适用于单个设备的操作或者不是特别紧急传输数据时,例如:管道设备、终端设备、单客户端的网络设备,阻塞 I/O 最常用、最简单、效率也最低。

非阻塞:非阻塞调用是指当请求的 I/O 操作不能完成时,即使不能立刻返回调用结果也不会阻塞当前进程,而是立即返回。

非阻塞 I/O 模型适用于 I/O 多路复用(一个进程处理多路数据),非阻塞 I/O 防止阻塞在 I/O 上,需要轮询。

多路复用 I/O 模型

I/O 多路复用允许同时检查多个文件描述符的一种机制

  • 内核添加一张表,监听表里面的信息,当有资源准备就绪,就执行

  • 资源 --文件描述符去除与否

  • 创建监听表


select()系统调用

系统调用 selec t会一直阻塞,直到一个或多个文件描述符集合成为就绪态。

#include 

int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

nfds:文件描述符的范围,即所有文件描述符的最大值加 1,不能出错

readfds:监听读资源的文件描述符集合

writefds:监听写资源的文件描述符集合

exceptfds:监听异常资源的文件描述符集合

timeout:NULL 一直等待, 或者根据 struct timeval 设置等待时间的上限值

struct timeval {
               long    tv_sec;           
               long    tv_usec;          
           };

readfds、writefds 和 exceptfds 所指向的结构体都是保存结果值的地方,在调用 select() 之前,这些参数指向的结构体必须初始化(通过 FD_ZERO() 和 FD_SET()),

返回值:成功返回已经准备就绪的文件描述符个数, 失败返回 -1

  • 返回 -1 表示有错误发生
  • 返回 0 表示在任何文件描述符成为就绪态之前 select() 调用已经超时
  • 返回一个正整数表示有一个或多个文件描述符已经处于就绪态

通常数据类型 fd_set 以位掩码的形式来实现

void FD_CLR(int fd, fd_set *set);    
int  FD_ISSET(int fd, fd_set *set);  
void FD_SET(int fd, fd_set *set);    
void FD_ZERO(fd_set *set);           

注意

select 正确返回时,会将准备好的文件描述符在集合中对应的位置置 1,其它位置全部置 0,为了保证任然可以监听其它没有 ready 的描述符,必须先将之前的集合保存下来

在 Linux 上,异常情况只会在以下两种情况下发生:

  • 连接到处于信包模式下的伪终端主设备上的从设备状态发生了改变
  • 流式套接字上接收到了带外数据

结构体 fd_set 的大小

linux-5.15.2includelinuxtypes.h
typedef __kernel_fd_set		fd_set;

linux-5.15.2includeuapilinuxposix_types.h
#define __FD_SETSIZE	1024

typedef struct {
	unsigned long fds_bits[__FD_SETSIZE / (8 * sizeof(long))];
} __kernel_fd_set;


poll()系统调用

系统调用 poll() 执行的任务同 select() 相似,主要区别在于如何指定待检查的文件描述符

在 select() 中,提供三个集合,在每个集合中标明所需的文件描述符

poll() 管理多个文件描述符进行轮询操作(查询文件描述符,如果有指定的事件发生立刻返回),根据文件描述的状态进行处理,一般通过返回值来确定事件是否发生,没有文件描述符个数的限制

poll() 指定时间内轮询指定文件描述符,如果有指定事件发生返回一个真值

#include 

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

参数 fds 列出了需要 poll() 来检查的文件描述符,该参数为 pollfd 结构体:

struct pollfd {
    int   fd;             
    short events;        
    short revents;        
};

参数 nfds 指定了结构体 fds 中元素的个数,nfds_t 实际为无符号整型

参数 timeout 决定了 poll() 的阻塞行为:

  • 如果 timeout 等于 -1,poll() 会一直阻塞直到 fds 中列出的文件描述符有一个达到就绪态(定义在对应的 events 字段中)或者捕获到一个信号
  • 如果 timeout 等于 0,poll() 不会阻塞,只执行一次检查,查看哪个文件描述符处于就绪态
  • 如果 timeout 大于 0,poll() 至多阻塞 timeout 毫秒,timeout 的精度受软件时钟粒度的限制

返回值:成功时 poll() 返回结构体中 events 域不为 0 的文件描述符个数,如果在超时前没有任何事件发生,poll() 会返回 0,失败返回 -1

  • 注意
  • select() 和 poll() 返回正整数时的细小差别,如果一个文件描述符在返回的描述符集合中出现不止一次,系统调用 select() 会将同一个描述符计数多次,而系统调用 poll() 返回的是就绪态的文件描述符个数,且一个文件描述符只会统计一次,就算在相应的 revents 字段中设定了多个位掩码也是如此
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/641753.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号