Linux 服务器编程学习笔记④
# Linux 高级 I/O 函数
# pipe 函数
#include <unistd.h>
int pipe (int fd[2]);
pipe 函数将一对打开的文件描述符值填入参数指定的数组内,成功返回 0,失败返回 -1 并设置 errno。
fd[1]写入的信息可以通过 fd[0] 读出,且是单工的,默认情况下为阻塞的。
此外,可以通过 socketpair 函数建立基于 UNIX 本地域协议族的双向通道:
#include <sys/types.h>
#include <sys/socket.h>
int socketpair (int domain, int type, int protocol, int fd[2]);
# dup & dup2 函数
#include <unistd.h>
int dup (int file_descriptor);
int dup2 (int file_descriptor_one, int file_descriptor_two);
dup 函数创建一个新的文件描述符,将新的文件描述符指向 file_descriptor 的文件(且返回的新的文件描述符总是系统当前可用的最小值)。dup2 函数创建的新的文件描述符的值便是我们传入的第二个参数 file_descriptor_two (若文件描述符此前已经打开,则其指向的打开文件会被替换为我们想要的)。调用失败时,都会返回 -1,并设置 errno。
注:创建的文件描述符不会继承原有属性。
# readv & writev 函数
#include <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);
这两个函数用于读写分散的内存块(iovec 类型),count 参数表示 vector 参数的长度。成功返回读写的字节数,失败时返回 -1 并设置 errno。
# sendfile 函数
#include <sys/sendfile.h>
ssize_t sendfile (int out_fd, int in_fd, off_t* offset, size_t count);
sendfile 函数在两个文件描述符之间直接传递数据(内核中操作),从而避免了在内核缓冲区和用户缓冲区之间的数据拷贝,效率很高,这被称为零拷贝。
成功时返回传输的字节数, 失败时返回 -1 并设置 errno。
注意,sendfile 函数中的 in_fd 必须是真实文件,out_fd 必须是 socket。(几乎就是为网络传输而生的函数)
# mmap & munmap 函数
mmap 函数用于申请一段内存空间,可将其作为进程间通信的共享内存,也可将文件直接映射到其中。munmap 函数则用于释放这段内存空间。
#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 则系统会自动分配),length 指定这段地址的长度,prot 指定访问权限(PROT_READ 可读,PROT_WRITE 可写,PROT_EXEC 可执行,PROT_NONE 不能被访问),flags 控制内存段内容被修改后的行为(MAP_SHARED 在进程间共享这段内存,即修改会被反映到文件中;MAP_PRIVATE进程私有,即修改不会反映到文件中),fd 表示被映射的文件, offset 表示被映射文件内容的开始位置。
mmap 执行成功时返回目标内存指针,失败返回 MAP_FAILED 并设置 errno。munmap 成功时返回 0,失败时返回 -1 并设置 errno。
# 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 是一个管道描述符则 off_in 必须设置为 NULL;fd_out 与 off_out 同理。len 表示要传输的数据长度。
成功时返回移动的字节数量,失败则返回 -1 并设置errno。
注意splice 函数要求 fd_in 和 fd_out 中必须有一个是管道文件描述符。(相当于通过管道进行缓冲)
# 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 都必须是管道描述符)。
成功返回在两个文件描述符间复制的数据量,失败返回 - 1并设置 errno。
# fcntl 函数
fcntl (file control) 函数提供了对文件描述符的各种控制操作。
#include <fcntl.h>
int fcntl(int fd, int cmd, ...)
fd 参数代表被操作的文件描述符,cmd 参数指定执行何种类型的操作。此处仅对网络编程中使用 fcntl 函数将一个文件描述符设置为非阻塞进行说明。
int setnoblocking(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;
}