当前位置: 首页 > news >正文

Linux 高级 I/O 函数——《Linux高性能服务器编程》第六章读书笔记

1、概述

什么是高级I/O函数

不是基础I/O函数的就是高级I/O函数,基础的I/O函数包括openread等。

本章重点介绍什么?

高级I/O函数一般不常用,本章重点介绍与网络编程相关的,他们大致可分为三类:

  • 用于创建文件描述符的函数,包括pipedup/dup2函数。
  • 用于读写数据的函数,包括readv/writevsendfilemmap/munmapsplicetee函数。
  • 用于控制I/O行为和属性的函数,包括fcntl函数

2、pipe 函数

pipe函数创建一个管道,以实现进程通信。本书在13.4节讨论如何使用管道实现进程间的哦通信,这里只介绍基本使用方法和注意事项。pipe函数定义如下:

#include<unistd.h>
int pipe(int fd[2]);

参数是一个长度为2的int数组。
该函数成功返回0,并将 一对 打开的文件描述符值填充到传入的fd数组中。其中fd[0]fd[1]分别是管道的两端。如果失败,返回-1并设置errno

注意事项

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

#include<sys/socket.h>
#include<sys/types.h>
int socketpair(int domain, int type, int protocol, int fd[2]);

在这里插入图片描述

2、dup函数和dup2函数

又时我们希望吧标准输入重定向到一个文件(类似于C++的ifstream),或者把标准输出重定向到一个网络连接(比如CGI编程)。这可以通过下面的用于复制文件描述符的dupdup2函数实现:

#include<unistd.h>
int dup(int file_descriptor);
int dup2(int file_descriptor_one, int file_descriptor_two);

dup函数返回一个新的文件描述符,该新文件描述符和原有文件描述符file_descriptor指向相同的 文件、管道或网络连接
dup返回的文件描述符总是取系统当前可用的最小的整数值
在这里插入图片描述

3、readvwritev函数

readv函数将数据从文件描述符读到分散的内存块中,即 分散读writev 函数则将多块分散的内存数据一并写入文件描述符中,即 集中写。他们的定义如下:

#inlcude<sys/uio.h>
ssize_t readv(int fd, const struct iovec* vector, int count);
ssize_t writev(int fd, const struct iovec* vector, int count);

参数说明:

  • fd是被读取 或 写入的文件描述符。
  • vector参数的类型是iovec结构体的数组(iovec是什么)。
  • count参数是vector数组的长度,即 有多少内存数据需要从fd读出或写入到fd

返回值:
readvwritev在成功时返回读出 或 写入fd的字节数,失败则返回-1并设置errno

这两个函数其实相当于简化版的recvmsgsendmsg:(复习一下)

#include<sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr* msg, int flags);
ssize_t sendmsg(int sockfd, struct msghdr* msg, int flags);

4、sendfile函数

sendfile函数在两个文件描述符之间直接传递数据(完全在内核中操作),从而避免了内核缓冲区和用户缓冲区之间的数据拷贝,效率很高,这被称为零拷贝sendfile函数定义如下:

#include<sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count);

参数说明:

  • in_fd参数是输出其内容的文件描述符。其实就是输入流。in_fd必须是一个支持类似mmap函数的文件描述符,即他必须指向真实的文件不能是socket和管道
  • out_fd参数是接收输出内容的文件描述符。out_fd必须是一个socket
  • offset参数指定从读入文件流的哪个位置开始读,如果为空(NULL),则使用读入文件流默认的起始位置。
  • count参数指定两个文件描述符之间传输的字节数。

in_fdout_fd的限制可见,该函数几乎是专门为在网络上传输文件而设计的。

返回值说明:

sendfile成功时返回传输的字节数,失败返回-1并设置errno

5、mmapmunmap函数

这两个函数可用于进程间共享内存。

mmap函数申请一段内存空间,我们可以将这段内存空间作为进程间通信的共享内存,也可以将文件直接映射到其中munmap函数则释放mmap创建的这段内存空间。他们的定义如下:

#include<sys/mman.h>
void* mmap(void* start, size_t length, int port, int flags, int fd, off_t offset);
int munmap(void* start, size_t length);

在这里插入图片描述
在这里插入图片描述

6、splice函数

splice函数用于在两个文件描述符之间移动数据,也是零拷贝操作。函数定义如下:

#include<fcntl.h>
ssize_t splice(int fd_in, loff_t* off_in, int fd_out, loff_t* off_out, size_t len, unsigned int flags);

参数说明:

  • fd_in输出其数据的文件描述符。就是输入流
  • off_in的含义fd_in代表的文件类型而改变
    ——若fd_in是管道文件描述符,那么off_in参数必须被设置为NULL
    ——若fd_in不是管道文件描述符,那它指向输入数据流中开始读取数据的位置。若被置为NULL,则表示从输入流的当前偏移位置读入
  • fd_out / off_out的含义与fd_in / off_in相同,不过用于输出数据流
  • len指定移动数据的长度。
  • flags参数控制数据如何移动,他可以被设置为下标中的某些值的按位或在这里插入图片描述

返回值说明:

splice函数调用成功时返回移动字节的数量。可能返回0,表示没有数据需要移动,这有可能发生在 从管道中读取数据而该管道中没有任何数据时。
失败时返回-1,并设置errno在这里插入图片描述

7、tee函数

tee函数在两个管道文件描述符之间复制数据,也是零拷贝操作。他不消耗数据,拷贝后,源文件描述符上的数据仍然可以用于后续的读操作。函数原型如下:

#include<fcntl.h>
ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);

参数说明:

其实和splice函数的参数意义相同,只不过输入流输出流必须是文件描述符

  • fd_in输入流
  • fd_out输出流

返回值:

成功返回在两个文件描述符之间复制的字节数,返回0表示没有复制任何数据。
失败时返回-1,并设置errno

8、fcntl(file control)函数

顾名思义,该函数用来对文件描述符执行各种控制操作。还有一个常见的控制文件描述符属性和行为的系统调用是ioctl,而且ioctlfcntl能够执行更多的控制。但是,只控制文件描述符常用的属性和行为fcntl函数是首选方法。其定义如下:

#include<fcntl.h>
int fcntl(int fd, int cmd, ...);

fd参数是被操作的文件描述符,cmd参数指定执行何种类型的操作。根据操作类型的不同,该函数可能还需要第三个可选参数。fcntl支持的常用操作及其参数如下表所示:
在这里插入图片描述
在这里插入图片描述
fcntl函数成功时的返回值如上表中 最后一列所示,失败则返回-1并设置errno

在网络编程中,fcntl函数通常用来将一个文件描述符设置为非阻塞的,如下面代码所示:

int set_nonblocking(int fd)
{
	int old_option = fcntl(fd, F_GETFL);		获取文件描述符旧的状态标志
	int new_option = old_option | O_NONBLOCK;	设置非阻塞标志
	fcntl(fd, F_SETFL, new_option);				
	return old_option;							返回文件描述符旧的状态标志,以便日后恢复该状态
}

在这里插入图片描述

相关文章:

  • Linux 服务器程序规范——《Linux高性能服务器编程》第7章——读书笔记
  • 高性能服务器程序框架——《Linux高性能服务器编程》第8章——读书笔记
  • 触发EPOLLIN 和 EPOLLOUT的所有情况
  • 红黑树(rbtree)、以及epoll的实现原理
  • epoll 的 ET,LT工作模式———实例程序
  • epoll 的EPOLLONESHOT 事件———实例程序
  • select 同时接收普通数据 和 带外数据
  • I/O复用的高级应用之一:非阻塞 connect———使用 select 实现(也可以用 poll 实现)
  • I/O复用的高级应用:同时处理 TCP 和 UDP 服务
  • I/O复用的高级应用:聊天室程序———实例代码
  • select、poll、epoll的使用方法 和 使用场景
  • 使用统一事件源的方式同时处理信号和 I/O
  • 使用SIGURG信号接受带外数据
  • 信号 ——《Linux高性能服务器编程》第10章——读书笔记
  • Linux 文件I/O 及其 多个相关函数
  • 分享的文章《人生如棋》
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • Asm.js的简单介绍
  • ES10 特性的完整指南
  • github指令
  • Kibana配置logstash,报表一体化
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • Swoft 源码剖析 - 代码自动更新机制
  • XML已死 ?
  • 第十八天-企业应用架构模式-基本模式
  • 多线程 start 和 run 方法到底有什么区别?
  • 设计模式 开闭原则
  • 适配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 屏幕尺寸及安全区域
  • 数组大概知多少
  • 转载:[译] 内容加速黑科技趣谈
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • #laravel 通过手动安装依赖PHPExcel#
  • (4)Elastix图像配准:3D图像
  • (Repost) Getting Genode with TrustZone on the i.MX
  • (附源码)ssm捐赠救助系统 毕业设计 060945
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (附源码)计算机毕业设计SSM疫情社区管理系统
  • (五)IO流之ByteArrayInput/OutputStream
  • (原創) 博客園正式支援VHDL語法著色功能 (SOC) (VHDL)
  • (转)Android学习笔记 --- android任务栈和启动模式
  • (轉)JSON.stringify 语法实例讲解
  • .bat批处理(三):变量声明、设置、拼接、截取
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况
  • .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary)
  • .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验
  • .secret勒索病毒数据恢复|金蝶、用友、管家婆、OA、速达、ERP等软件数据库恢复
  • /*在DataTable中更新、删除数据*/
  • ??如何把JavaScript脚本中的参数传到java代码段中
  • @DependsOn:解析 Spring 中的依赖关系之艺术
  • @property @synthesize @dynamic 及相关属性作用探究
  • [120_移动开发Android]008_android开发之Pull操作xml文件
  • [20161214]如何确定dbid.txt