0

0

【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力

雪夜

雪夜

发布时间:2025-04-18 12:02:03

|

816人浏览过

|

来源于php中文网

原创

如何理解io?

IO指的是计算机系统中输入(Input)和输出(Output)的过程,以计算机本身为参照物,是计算机与外部设备进行数据交互的机制。

输入(Input)是向计算机发送数据的过程,而输出(Output)是从计算机向外部设备发送数据的过程。

IO操作主要包括等待和拷贝两个步骤:

IO = 等待 + 拷贝(等待是主要矛盾)

在等待外部设备准备好数据后,CPU通过针脚发送中断信号通知操作系统。操作系统进入内核态,进行数据拷贝。

因此,IO操作基本可以概括为等待和拷贝两个动作。

高效IO

在IO操作中,时间主要消耗在等待上,因为拷贝的时间相对于等待来说要短得多。

高效的IO操作意味着减少等待时间,从而增加拷贝操作在整个过程中的比重。

【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力

第一种IO模型:阻塞IO模型

阻塞IO模型的特点是在系统调用时,如果外部设备未准备好数据,进程会一直等待数据准备就绪。一旦数据准备好,数据就会从内核空间拷贝到用户空间,并返回成功标识符。

【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);

第二种IO模型:非阻塞IO模型

非阻塞IO模型与阻塞IO模型的最大区别在于,当没有数据可用时,非阻塞IO会立即返回,并返回EWOULDBLOCK错误码。

【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力

#include 
#include 
#include 
using namespace std;
void SetNoBlock(int fd){
    int info=fcntl(fd,F_GETFL);
    if(info

第三种IO模型:信号驱动IO模型

在信号驱动IO模型中,当内核准备好数据时,会使用SIGIO信号通知应用程序进行IO操作。

与非阻塞IO不同的是,信号驱动IO不会循环检测数据是否准备好,而是当数据真正可用时发送SIGIO信号,确保IO操作成功。

【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力


第四种IO模型:IO多路转接模型

IO多路转接模型包括select、poll和epoll等方法。通过允许单个线程同时监控多个文件描述符的I/O状态,可以避免为每个I/O操作创建单独线程,从而减少资源消耗和上下文切换开销。

虽然图示上看起来与阻塞IO模型类似,但IO多路转接的关键在于可以一次性等待多个文件的状态变化(一切皆文件)。

【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力


第五种IO模型:异步IO模型

艺映AI
艺映AI

艺映AI - 免费AI视频创作工具

下载

前四种模型都是同步IO,因为它们参与了等待或拷贝的过程。阻塞IO参与了等待和拷贝,非阻塞IO至少参与了拷贝,IO多路转接可以管理多个文件并设置为非阻塞。

异步IO则直接返回,等待和拷贝的过程都由系统完成。处理完成后,系统通过事件、信号等方式通知应用程序。

【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力


同步通信和异步通信

同步通信需要参与等待和拷贝的过程,参与其中任何一个步骤即为同步。

异步通信虽然也需要等待和拷贝,但这两个过程完全由系统完成,调用者无需关心这两个过程。系统处理完毕后会通知调用者。

需要注意的是,线程同步和线程互斥与此概念不同。它们是为了保护临界资源,确保资源的一致性。


阻塞和非阻塞

阻塞调用会在调用成功之前挂起线程,直到得到结果后才返回。

非阻塞调用会立即返回,不会阻塞线程。


fcntl函数

文件描述符默认是阻塞的。

函数原型

#include 
#include 
int fcntl(int fd, int cmd, ... /* arg */ );

cmd是命令,指定操作类型。主要操作类型包括:

  1. 获取、设置文件状态信息:cmd=F_GETFL,F_SETFL。
  2. 复制现有描述符:cmd=F_DUPFD。
  3. 获取、设置文件描述符标志:cmd=F_GETFD,F_SETFD。
  4. 获取、设置异步IO所有权:cmd=F_GETOWN,F_SETOWN。
  5. 获取、设置记录锁:cmd=F_GETLK,F_SETLK,F_SETLKW。
cmd 功能
F_GETFL,F_SETFL 获取、设置文件状态信息
F_DUPFD 复制现有描述符
F_GETFD,F_SETFD 获取、设置文件描述符标志
F_GETOWN,F_SETOWN 获取、设置异步IO所有权
F_GETLK,F_SETLK,F_SETLKW 获取、设置记录锁

根据cmd的不同,可能需要传递额外的参数。例如,设置类的操作需要加入文件状态信息,如O_NONBLOCK用于设置非阻塞模式。

F_DUPFD功能

在F_DUPFD中,返回新的文件描述符,可以设置新描述符的最小值。如果该值已被占用,则生成一个比该值更大的描述符。

#include 
#include 
#include 
using namespace std;
int main() {
    int fd = open("example.txt", O_RDONLY|O_CREAT);
    if (fd == -1) {
        perror("open");
        return 1;
    }
    int new_fd = fcntl(fd, F_DUPFD, 20); // 复制文件描述符,新描述符值大于等于10
    if (new_fd == -1) {
        perror("fcntl");
        close(fd);
        return 1;
    }
    printf("Original fd: %d, New fd: %d\n", fd, new_fd);
    cout

【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力

F_GETFL和F_SETFL功能

使用F_GETFLF_SETFL命令可以获取和设置文件状态标志。文件状态标志包括O_APPENDO_NONBLOCK等。

非阻塞:O_NONBLOCK。

#include 
#include 
#include 
using namespace std;
void SetNoBlock(int fd){
    int info=fcntl(fd,F_GETFL);
    if(info

结束语

至此,我们已经深入探讨了计算机科学中的诸多重要概念,包括I/O操作、线程同步与互斥、文件描述符管理等。理解这些概念对于编写高效、可靠的程序至关重要。希望本文能够为您的学习和实践提供有益的参考。如果您在实际编程中遇到任何问题,建议查阅相关文档或进一步研究具体案例。感谢您的阅读,祝您在编程的道路上不断进步!

相关专题

更多
mysql标识符无效错误怎么解决
mysql标识符无效错误怎么解决

mysql标识符无效错误的解决办法:1、检查标识符是否被其他表或数据库使用;2、检查标识符是否包含特殊字符;3、使用引号包裹标识符;4、使用反引号包裹标识符;5、检查MySQL的配置文件等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

182

2023.12.04

Python标识符有哪些
Python标识符有哪些

Python标识符有变量标识符、函数标识符、类标识符、模块标识符、下划线开头的标识符、双下划线开头、双下划线结尾的标识符、整型标识符、浮点型标识符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

280

2024.02.23

java标识符合集
java标识符合集

本专题整合了java标识符相关内容,想了解更多详细内容,请阅读下面的文章。

254

2025.06.11

c++标识符介绍
c++标识符介绍

本专题整合了c++标识符相关内容,阅读专题下面的文章了解更多详细内容。

121

2025.08.07

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

482

2023.08.10

点击input框没有光标怎么办
点击input框没有光标怎么办

点击input框没有光标的解决办法:1、确认输入框焦点;2、清除浏览器缓存;3、更新浏览器;4、使用JavaScript;5、检查硬件设备;6、检查输入框属性;7、调试JavaScript代码;8、检查页面其他元素;9、考虑浏览器兼容性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

182

2023.11.24

磁盘配额是什么
磁盘配额是什么

磁盘配额是计算机中指定磁盘的储存限制,就是管理员可以为用户所能使用的磁盘空间进行配额限制,每一用户只能使用最大配额范围内的磁盘空间。php中文网为大家提供各种磁盘配额相关的内容,教程,供大家免费下载安装。

1349

2023.06.21

如何安装LINUX
如何安装LINUX

本站专题提供如何安装LINUX的相关教程文章,还有相关的下载、课程,大家可以免费体验。

704

2023.06.29

Java JVM 原理与性能调优实战
Java JVM 原理与性能调优实战

本专题系统讲解 Java 虚拟机(JVM)的核心工作原理与性能调优方法,包括 JVM 内存结构、对象创建与回收流程、垃圾回收器(Serial、CMS、G1、ZGC)对比分析、常见内存泄漏与性能瓶颈排查,以及 JVM 参数调优与监控工具(jstat、jmap、jvisualvm)的实战使用。通过真实案例,帮助学习者掌握 Java 应用在生产环境中的性能分析与优化能力。

19

2026.01.20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.5万人学习

Django 教程
Django 教程

共28课时 | 3.3万人学习

Excel 教程
Excel 教程

共162课时 | 12.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号