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

如何理解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模型

文心大模型 文心大模型

百度飞桨-文心大模型 ERNIE 3.0 文本理解与创作

文心大模型 56 查看详情 文心大模型

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

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

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

同步通信和异步通信

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

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

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

阻塞和非阻塞

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

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

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: %dn", 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操作、线程同步与互斥、文件描述符管理等。理解这些概念对于编写高效、可靠的程序至关重要。希望本文能够为您的学习和实践提供有益的参考。如果您在实际编程中遇到任何问题,建议查阅相关文档或进一步研究具体案例。感谢您的阅读,祝您在编程的道路上不断进步!

以上就是【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/511598.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月9日 01:02:59
下一篇 2025年11月9日 01:07:31

相关推荐

  • Go语言中高效管理并发外部命令执行:构建Goroutine工作池

    本文探讨了在go语言中高效管理并发外部命令执行的策略,特别是如何避免因大量goroutine同时启动而导致的资源耗尽和程序过早退出。通过构建一个基于通道(channel)和`sync.waitgroup`的goroutine工作池,我们可以精确控制并行执行的外部进程数量,实现任务的动态调度和资源的优…

    好文分享 2025年12月16日
    000
  • Go语言中JSON整数键的解码与高效转换实践

    本文深入探讨了go语言`encoding/json`包在处理json对象时,为何其键必须为字符串类型,以及当json数据包含数字作为键时,如何高效地将其解码并转换为`map[int]t`类型。文章将提供详细的解释和实用的go代码示例,帮助开发者理解并实现这一转换过程,确保数据处理的准确性和内存效率。…

    2025年12月16日
    000
  • Golang 模板解析失败:空白页问题分析与解决

    本文旨在解决 Golang 模板解析时出现空白页的问题。通过分析 `template.ParseFiles` 和 `template.New` 的差异,解释了模板名称不匹配导致的问题,并提供了两种解决方案:一是确保模板名称与文件名一致,二是使用 `ExecuteTemplate` 显式指定要执行的模…

    2025年12月16日
    000
  • 如何在Golang中实现DevOps监控报警

    集成Prometheus暴露指标,使用OpenTelemetry实现链路追踪,通过Alertmanager或Webhook对接告警通知,结合Zap日志与Loki实现日志监控联动,构建Golang服务可观测性闭环。 在Golang中实现DevOps监控报警,核心是将应用运行状态数据采集、上报,并与告警…

    2025年12月16日
    000
  • Golang模板解析空白页问题详解与解决方案

    本文旨在解决Golang模板解析时出现空白页的问题。通过分析`template.ParseFiles`和`template.New`的使用差异,揭示问题根源在于模板命名不匹配。提供两种解决方案:一是使用与文件名相同的模板名,二是使用`ExecuteTemplate`显式指定要执行的模板,帮助开发者避…

    2025年12月16日
    000
  • 在Gorilla Mux中创建带可选URL变量的路由

    本文详细介绍了如何在go语言的gorilla mux路由框架中实现带有可选url变量的路由。核心策略是为同一处理函数注册多个路由模式,一个包含变量,另一个不包含。在处理函数内部,通过检查`mux.vars`返回的变量是否存在来适配不同的请求路径,从而优雅地处理有无特定参数的场景,确保路由的灵活性和代…

    2025年12月16日
    000
  • Go语言中优雅地中断并发任务:使用通道和Select实现精确控制

    在go语言中,直接中断一个正在执行的`time.sleep`操作并非易事,因为`time.sleep`会阻塞当前goroutine。本文将深入探讨如何避免使用阻塞的`time.sleep`进行并发控制,转而利用go的通道(channels)和`select`语句,实现goroutine间的安全通信与…

    2025年12月16日
    000
  • Go语言defer机制深度解析:能否获取其函数引用?

    go语言的`defer`机制用于资源清理,其内部调用列表是运行时实现细节,不提供直接访问。本文探讨了获取`defer`函数引用的可行性,强调了go语言不鼓励此类操作,并提供了安全的惯用模式来管理初始化和清理逻辑。尽管存在通过`cgo`和`unsafe`进行底层探索的示例,但强烈建议避免在生产环境中使…

    2025年12月16日
    000
  • 使用 Go 语言进行原始套接字编程

    本文旨在指导开发者如何使用 Go 语言进行原始套接字编程,以实现自定义网络数据包的发送和接收。重点介绍使用 go.net/ipv4 库创建和操作原始套接字,以及如何构造自定义 IP 头部来实现源 IP 地址欺骗等高级网络功能。同时,也强调了使用原始套接字的安全风险和权限要求。 在某些网络编程场景下,…

    2025年12月16日
    000
  • 深入理解Go语言的defer机制:原理、限制与替代方案

    go语言的`defer`语句用于安排函数在当前函数返回前执行,其内部实现与特定运行时(如goroutine和栈帧)紧密关联,因此无法通过标准go语言可靠地获取或直接调用已延迟的函数引用。尽管通过cgo和`unsafe`包存在低级访问的可能性,但这被强烈不推荐。对于需要共享资源清理逻辑的场景,go语言…

    2025年12月16日
    000
  • 如何在Golang中实现策略模式动态切换行为

    通过接口定义行为并由不同结构体实现,Golang中策略模式可动态切换支付方式,避免条件判断,提升扩展性。 在Golang中实现策略模式,核心是通过接口定义行为,让不同策略结构体实现该接口,从而在运行时动态切换具体行为。这种方式避免了大量条件判断,提升了代码的可扩展性和可维护性。 定义策略接口 先定义…

    2025年12月16日
    000
  • Go 语言反射:通过字段名获取并转换底层结构体切片

    本文深入探讨 Go 语言中如何利用反射机制,通过字段名动态获取结构体中的底层切片字段。我们将展示 `reflect.Value.Interface()` 结合类型断言的强大功能,它能将反射值安全地转换回具体的 Go 类型,从而避免在后续操作中持续使用反射,实现更自然、高效的代码编写。 在 Go 语言…

    2025年12月16日
    000
  • Go语言实现树莓派GPIO控制:davecheney/gpio 包入门

    本教程旨在介绍如何使用go语言在树莓派上进行gpio操作。我们将重点探讨`davecheney/gpio`包,这是一个流行的go语言库,用于简化对树莓派硬件引脚的控制。通过具体的代码示例,读者将学习如何初始化gpio、设置引脚模式以及执行基本的输入/输出操作,从而实现如读取传感器数据或控制外部设备等…

    2025年12月16日
    000
  • Go语言并发文件下载器:解决文件损坏问题与优化实践

    本文深入探讨go语言中基于http range头实现并发文件下载的机制。针对并发写入文件时常见的损坏问题,重点分析了`os.o_append`与`os.write`在多协程环境下的局限性,并提出了使用`os.writeat`进行精确位置写入的解决方案。文章还提供了优化后的代码示例,并强调了错误处理、…

    2025年12月16日
    000
  • Go并发编程:安全地向共享切片追加数据

    本文深入探讨了在go语言中,多个goroutine并发向同一个切片追加数据时面临的数据竞争问题。我们将介绍三种实现并发安全的策略:利用sync.mutex进行互斥访问以保护共享资源、通过通道(channel)机制收集并统一处理结果,以及在切片最终大小已知时,采用预分配并按索引写入的无锁高效方法。旨在…

    2025年12月16日
    000
  • Go语言在Fish Shell中的GOPATH正确配置指南

    本文旨在解决go语言开发者在使用fish shell时,因gopath环境变量配置不当导致的”cannot find package”错误。核心解决方案在于理解fish shell的变量导出机制,即在`~/.config/fish/config.fish`文件中使用`set …

    2025年12月16日
    000
  • Go语言实现高效多线程文件下载器:基于HTTP Range与并发控制

    本文详细介绍了如何使用go语言构建一个高效的多线程文件下载器。通过利用http `range` 请求头实现文件分块下载,并结合go的并发特性及`os.file.writeat`方法,实现在指定偏移量写入数据。文章强调了正确的并发控制、文件预分配、错误处理和分块逻辑的重要性,并提供了一个优化后的代码示…

    2025年12月16日
    000
  • Golang中解析动态JSON键的实践指南

    本文探讨了在go语言中如何有效解析包含动态顶级键的json字符串。通过将动态键映射为`map[string]struct`的结构,我们可以灵活地提取嵌套在这些动态键下的特定字段,如姓名和年龄,从而实现对复杂json数据的结构化访问。 在Go语言中处理JSON数据是常见的任务,encoding/jso…

    2025年12月16日
    000
  • 解码十六进制字符串时避免 “index out of range” 错误

    本文旨在帮助开发者避免在使用 Go 语言的 `encoding/hex` 包进行十六进制字符串解码时遇到的 “index out of range” 错误。通过示例代码和详细解释,我们将展示如何正确地分配目标切片,确保解码操作能够顺利进行,并获得预期的结果。 在使用 Go 语…

    2025年12月16日
    000
  • 在Gorilla Mux中实现可选URL变量的路由配置

    本文将详细介绍如何在go语言的gorilla mux路由框架中实现带有可选url变量的路由配置。通过注册多个路径模式来覆盖有无参数的场景,并指导开发者如何在处理函数中安全地获取和判断这些可选参数的存在,从而优雅地处理不同的url请求模式。 理解Gorilla Mux中可选URL参数的挑战 在构建We…

    2025年12月16日
    000

发表回复

登录后才能评论
关注微信