IT袋

当前位置:主页 > 经验教程 > 系统教程 >

Linux

Linux I/O模型详解(3)

时间:2024-01-14 17:25:08 来源:IT袋 作者:马勇
导读:Linux,从上面的程序中不难发现:非阻塞调用模式下,所有客户端的链接需要在程序中自己管理,进程(现成)需要不停的循环遍历每个链接是否可读、 可写、关闭

Linux

从上面的程序中不难发现:非阻塞调用模式下,所有客户端的链接需要在程序中自己管理,进程(现成)需要不停的循环遍历每个链接是否可读、 可写、关闭连接, 大大增加了网络编程的难度。

这种模式存在以下的问题:

  • 程序需要管理每个链接, 增加了应用程序的复杂度;
  • 每次循环需要遍历每个链接, 即使该连接没有数据达到, 造成资源浪费;
  • 遍历每个链接, 调用 read 、write 都需要转到内核空间处理, 频繁的内核态和用户态的切换。

select

select 解决了非阻塞调用的部分问题,select 是一种 I/O 多路复用模型,它具有以下优势:

  1. 高效的并发处理:select 允许一个进程同时管理多个文件描述符(sockets、文件、标准输入等),它可以监视多个文件描述符,并在它们中的任何一个变为可读、可写时通知应用程序。这使得一个进程可以有效地处理大量并发连接,而无需为每个连接创建一个新线程或进程,减少了资源消耗。
  2. 简单的编程模型:使用 select 可以让开发者避免复杂的多线程或多进程编程,开发者可以在一个单一的事件循环中处理多个连接,而不必担心线程同步和互斥。
  3. 跨平台性:select 是一个标准的 POSIX 系统调用,因此它在大多数 UNIX-like 操作系统上可用,包括 Linux、macOS 和各种 BSD 变种。它还在 Windows 平台上有对应的实现,如 select()、WSASelect()。
  4. 支持非阻塞 I/O:select 允许将文件描述符设置为非阻塞模式,从而实现非阻塞 I/O。这意味着应用程序可以继续执行其他任务,而不必等待数据准备好。
  5. 可定制性:select 允许应用程序监视不同类型的事件,如可读、可写、异常等,这使得开发者能够自定义事件处理逻辑,以适应各种应用场景。

我们先看下 select 函数的定义

// 返回:若有就绪描述符则为其数目,若超时则为 0,若出错则为 -1
int select(int maxfd, 
     fd_set *readset, 
     fd_set *writeset, 
     fd_set *exceptset, 
     const struct timeval *timeout);

select 参数的含义如下:

  • maxfd:待监控的描述符基数,为待测试的最大描述符加 1。
  • readset/writeset/exceptset:分别为读描述符集合、写描述符集合、异常描述符集合,这三个分别通知内核,在哪些描述描述符上检测数据可以读、可写、有异常事件发生。
  • timeout:可以设置阻塞时间,如果为 null 代表一直阻塞。

简单来说,select 可以让程序不用再创建一个列表来管理所有的连接, 而是将所有的加入 select 的对应集合中,由 select 去内核查询每个连接对应的事件。

相关阅读