总结《Linux高性能服务器编程》第六章
第六章 高级I/O函数
pipe函数
-
pipe函数可用于创建一个管道,以实现进程间通信,pipe函数的定义如下
#include<unistd.h> int pipe(int fd[2]);
- 参数:一个包含两个int型整数的数组指针;
- 成功时返回0,并将一对打开的文件描述符值填入其参数指向的数组,失败则返回-1;
-
通过pipe函数创建的这两个文件描述符fd[0]和fd[1]分别构成管道的两端,往fd[1]写入的数据可以从fd[0]读出,并且fd[0]只能从管道读出数据,fd[1]则只能往管道写入数据,而不能反过来使用;
-
管道内部传输的数据是字节流,且管道本身拥有容量限制;
-
socketpair函数能够方便地创建双向管道;
#include<sys/types.h> #include<sys/socket.h> int socketpair(int domain,int type,int protocol,int fd[2]);
dup函数和dup2函数
-
用于复制文件描述符的dup或dup2函数:把标准输入重定向到一个文件,或者把标准输出重
定向到一个网络连接;#include<unistd.h> int dup(int file_descriptor); int dup2(int file_descriptor_one,int file_descriptor_two);
- dup函数创建一个新的文件描述符,该新文件描述符和原有文件描述符file_descriptor指向相同的文件、管道或者网络连接,并且dup返回的文件描述符取系统当前可用的最小整数值;
- dup2和dup类似,不过它将返回第一个不小于file_descriptor_two的整数值;
-
通过dup和dup2创建的文件描述符并不继承原文件描述符的属性,比如close-on-exec和non-blocking等;
代码清单6-1 用dup函数实现CGI服务器原理
readv函数和writev函数
-
readv函数:将数据从文件描述符读到分散的内存块中,即分散读;
-
writev函数:将多块分散的内存数据一并写入文件描述符中,即集中写;
#include<sys/uio.h> size_t readv(int fd, const struct iovec*vector,int count); size_t writev(int fd, const struct iovec*vector,int count);
- vector参数的类型是iovec结构数组,该结构体描述一块内存区;
- count参数是vector数组的长度;
- 相当于简化版的recvmsg和sendmsg函数;
sendfile函数
-
sendfile函数在两个文件描述符之间直接传递数据(完全在内核中操作),从而避免了内核缓冲区和用户缓冲区之间的数据拷贝,效率很高,被称为零拷贝;
#include<sys/sendfile.h> size_t sendfile(int out_fd,int in_fd,off_t*offset,size_t count);
- in_fd必须指向真实文件,不能是socket和管道,而out_fd则必须是一个socket;
mmap函数和munmap函数
-
mmap函数用于申请一段内存空间。我们可以将这段内存作为进程间通信的共享内存,也可以将文件直接映射到其中,munmap函数则释放由mmap创建的这段内存空间;
#include<sys/mman.h> void* mmap(void*start,size_t length,int prot,int flags,int fd,off_t offset); int munmap(void*start,size_t length);
- start参数允许用户使用特定地址作为这段内存的起始地址,如果为NULL则由系统自动分配;
- prot参数用来设置内存段的访问权限:PROT_READ(内存段可读)/ PROT_WRITE(内存段可写) /PROT_EXEC(内存段可执行) /PROT_NONE(内存段不能被访问);
- flags参数控制内存段内容被修改后程序的行为;
splice函数
-
splice函数用于在两个文件描述符之间移动数据,是零拷贝操作;
#include<fcntl.h> size_t splice(int fd_in, loff_t* off_in, int fd_out, loff_t* off_out, size_t len, unsigned int flags);
- off_in/off_out表示从输入/输出数据流的何处开始读取/写入数据;
- flags参数则控制数据如何移动;
-
使用splice函数时,fd_in和fd_out必须至少有一个是管道文件描述符;
tee函数
-
tee函数在两个管道文件描述符之间复制数据,是零拷贝操作;
#include<fcntl.h> size_t tee(int fd_in,int fd_out,size_t len,unsigned int flags);
- tee函数*不消耗数据,因此源文件描述符上的数据仍然可以用于后续的读操作;
fcntl函数
-
fcntl函数(file control)提供了对文件描述符的各种控制操作;
#include<fcntl.h> int fcntl(int fd,int cmd,…);
- 另一个常见控制文件描述符的系统调用是ioctl,但fcntl函数是由POSIX规范指定的首选方法;
- 在网络编程中,fcntl函数通常用来将一个文件描述符设置为非阻塞的;
