与网络编程相关的I/O函数大概可以分三类:
- 用于创建文件描述符的函数:包括 pipe、dup/dup2
- 用于读写数据的函数:包括 readv/writev、sendfile、mmap/munmap、splice 和 tee
- 用于控制I/O行为和属性的函数:包括 fcntl 函数
pipe函数
pipe 函数用于创建一个管道,以实现进程间通信。
#include<unistd.h>
int pipe(int fd[2]);
参数是一个包含两个 int 型整数的数组指针。
成功:返回 0 ,并将一对打开的文件描述符值传入数组中。
失败:返回 -1,并设置errno。
通过 pipe 函数创建的两个文件描述符 fd[0] 和 fd[1] 分别构成管道的两端。fd[0] 用于从管道中读出,fd[1] 用于向管道中写入。如果要实现双向通信,就需要使用两个管道。默认情况下,这一对文件描述符都是阻塞的。
管道内部传输的数据时字节流,管道容量的大小默认是 65535 字节,可以使用 fcntl 函数修改管道容量。
dup函数和dup2函数
重定向,例如将标准输入重定向到一个文件,或者把标准输出重定向到一个网络连接(比如 CGI 编程)。
/include<unistd.h>
int dup(int file_descriptor);
int dup2(int file_descriptor_one, int file_descriptor_two);
dup函数:创建一个新的文件描述符,新的文件描述符和原来的 file_descriptor 指向同一个文件、管道或网络连接。并且 dup返回的文件描述符总是取系统当前可用的最小整数值。
dup2函数:返回第一个不小于 file_descriptor 的第一个整数。
sendfile
sendfile 函数:在两个文件描述符之间直接传递数据(完全在内核中操作),从而避免了从内核缓冲区和用户缓冲区之间的数据拷贝,效率高,被称为零拷贝。
#include<sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count);
sffset:指定从哪个位置开始读,为空则默认起始位置。
count:读多少字节。
注意:in_df 必须指向真实的文件,不能是管道 和 socket ,out_fd 必须是一个 socket 。可见 sendfile 是专门为网络传输而设计的。
mmap函数和munmap
mmap 函数:用于申请一段内存空间,可以将这段内存作为进程间通信的共享内存,也可以将文件直接映射到其中。
munmap 函数:释放由 mmap 函数创建的内存空间。
#include<sys/mman.h>
void* mmap(void* start, size_t length, int prot, int flags, int fd, sff_t offset);
int munmap(void* start, size_t length);
start:这段内存的起始地址。设置为 NULL ,系统自动分配地址。
legth:内存段的长度。
prot:设置内存段的访问权限。可以取以下的按位或:RROT_READ,内存段可读。RROT_WRITE,内存段可写。RROT_EXEC,内存段可执行。RROT_NONE,内存段不能被访问。
flags:控制内存段内容被修改后程序的行为。
fd:被映射文件对应的文件描述符。
mmap->成功:返回目标内存区域指针。 失败:返回MAP_FAILED((void*)-1)并设置 errno 。
munmap->成功:返回 0 。 失败:返回 -1 并设置 errno 。
fcntl函数
fcntl 函数:(file control)提供了对文件描述符的各种控制操作。
#include<fcntl.h>
int fcntl(int fd, int cmd,...);
cmd参数:指定执行何种类型的操作,根据类型的不同,可能会有第三个参数 arg 。
在网络编程中,fcntl 函数通常用来将一个文件描述符设置为非阻塞的。