【Linux网络】I/O技术深度解析:五模型与fcntl函数
时间:2025-04-20 18:13:08 470浏览 收藏
本文深入探讨了Linux系统中的五种I/O模型:阻塞IO、非阻塞IO、信号驱动IO、IO多路转接和异步IO,并详细解析了`fcntl`函数在I/O操作中的应用。文章首先阐述了I/O操作的本质——等待和数据拷贝,并指出高效I/O的关键在于减少等待时间。随后,分别对五种I/O模型进行了详细的比较和分析,并结合代码示例讲解了`fcntl`函数的用法,尤其关注`F_GETFL`和`F_SETFL`命令在设置非阻塞模式中的应用,旨在帮助读者理解和掌握Linux网络编程中的I/O技术。
如何理解IO?
IO指的是计算机系统中输入(Input)和输出(Output)的过程,以计算机本身为参照物,是计算机与外部设备进行数据交互的机制。
输入(Input)是向计算机发送数据的过程,而输出(Output)是从计算机向外部设备发送数据的过程。
IO操作主要包括等待和拷贝两个步骤:
IO = 等待 + 拷贝(等待是主要矛盾)
在等待外部设备准备好数据后,CPU通过针脚发送中断信号通知操作系统。操作系统进入内核态,进行数据拷贝。
因此,IO操作基本可以概括为等待和拷贝两个动作。
高效IO
在IO操作中,时间主要消耗在等待上,因为拷贝的时间相对于等待来说要短得多。
高效的IO操作意味着减少等待时间,从而增加拷贝操作在整个过程中的比重。
第一种IO模型:阻塞IO模型
阻塞IO模型的特点是在系统调用时,如果外部设备未准备好数据,进程会一直等待数据准备就绪。一旦数据准备好,数据就会从内核空间拷贝到用户空间,并返回成功标识符。
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错误码。
#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操作成功。
第四种IO模型:IO多路转接模型
IO多路转接模型包括select、poll和epoll等方法。通过允许单个线程同时监控多个文件描述符的I/O状态,可以避免为每个I/O操作创建单独线程,从而减少资源消耗和上下文切换开销。
虽然图示上看起来与阻塞IO模型类似,但IO多路转接的关键在于可以一次性等待多个文件的状态变化(一切皆文件)。
第五种IO模型:异步IO模型
前四种模型都是同步IO,因为它们参与了等待或拷贝的过程。阻塞IO参与了等待和拷贝,非阻塞IO至少参与了拷贝,IO多路转接可以管理多个文件并设置为非阻塞。
异步IO则直接返回,等待和拷贝的过程都由系统完成。处理完成后,系统通过事件、信号等方式通知应用程序。
同步通信和异步通信
同步通信需要参与等待和拷贝的过程,参与其中任何一个步骤即为同步。
异步通信虽然也需要等待和拷贝,但这两个过程完全由系统完成,调用者无需关心这两个过程。系统处理完毕后会通知调用者。
需要注意的是,线程同步和线程互斥与此概念不同。它们是为了保护临界资源,确保资源的一致性。
阻塞和非阻塞
阻塞调用会在调用成功之前挂起线程,直到得到结果后才返回。
非阻塞调用会立即返回,不会阻塞线程。
fcntl函数
文件描述符默认是阻塞的。
函数原型
#include#include int fcntl(int fd, int cmd, ... /* arg */ );
cmd是命令,指定操作类型。主要操作类型包括:
- 获取、设置文件状态信息:cmd=F_GETFL,F_SETFL。
- 复制现有描述符:cmd=F_DUPFD。
- 获取、设置文件描述符标志:cmd=F_GETFD,F_SETFD。
- 获取、设置异步IO所有权:cmd=F_GETOWN,F_SETOWN。
- 获取、设置记录锁: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
F_GETFL和F_SETFL功能
使用F_GETFL
和F_SETFL
命令可以获取和设置文件状态标志。文件状态标志包括O_APPEND
、O_NONBLOCK
等。
非阻塞:O_NONBLOCK。
#include#include #include using namespace std; void SetNoBlock(int fd){ int info=fcntl(fd,F_GETFL); if(info
结束语
至此,我们已经深入探讨了计算机科学中的诸多重要概念,包括I/O操作、线程同步与互斥、文件描述符管理等。理解这些概念对于编写高效、可靠的程序至关重要。希望本文能够为您的学习和实践提供有益的参考。如果您在实际编程中遇到任何问题,建议查阅相关文档或进一步研究具体案例。感谢您的阅读,祝您在编程的道路上不断进步!
好了,本文到此结束,带大家了解了《【Linux网络】I/O技术深度解析:五模型与fcntl函数》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多文章知识!
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
452 收藏
-
278 收藏
-
376 收藏
-
115 收藏
-
160 收藏
-
455 收藏
-
111 收藏
-
251 收藏
-
449 收藏
-
448 收藏
-
427 收藏
-
449 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习