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

本文介绍了高级I/O函数在Linux系统中的应用,包括pipe、dup/dup2、readv/writev、sendfile、mmap/munmap、splice和tee等,这些函数常用于网络编程和进程间通信。重点讨论了sendfile的零拷贝特性,以及fcntl在设置文件描述符非阻塞模式中的作用。通过这些函数,开发者能更高效地处理文件和网络数据传输。
摘要由CSDN通过智能技术生成

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;							返回文件描述符旧的状态标志,以便日后恢复该状态
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值