高级 I/O 函数
本文是《Linux 高性能服务器编程》阅读记录,供以后查阅参考。推荐阅读原书。
所有函数未标明需要包含什么头文件,可使用
man
命令自行查询。
1. pipe
函数声明:
1 |
|
fd[1]
用于 写入
数据;fd[0]
用于 读取
数据。且管道为单向通信,只能一端写入,另一端读取。需要双向通信时,可创建两个管道。管道默认为阻塞的,也即调用
read
函数读数据时,若管道内无数据写入,read
调用会阻塞,直到有数据可读。write
调用当管道已满时,也会阻塞,直到管道有足够的空闲空间可供写入数据。
如果写入端引用计数为 0,调用 read
会返回 0,表示
EOF(End Of File);如果读取端引用计数为 0,调用 write
将失败,并引发 SIGPIPE
信号。
另外,可使用 sockerpair
函数创建双向通信的管道,即:两端都可以读写:
1 |
|
2. dup 和 dup2
函数原型:
1 |
|
dup
函数用于创建一个新的指向同一个文件、管道或网络连接的文件描述符。dup2
关闭 fd2
,并且将 fd2
指向 fd
表示的文件。
3. readv 和 writev
readv
函数将数据从文件描述符读到分散的内存块中,即:分散读;writev
函数则将多块分散的内存数据一并写入一个文件描述符,即:集中写。函数声明如下:
1 |
|
成功时返回读取的字节数;失败返回 -1。
writev
函数的一个可能的使用场景是:响应 HTTP
请求时,header 和 body 分别存储在两个缓冲区里。可以利用
writev
函数一次写两个缓冲区。
4. sendfile
sendfile
函数用于在两个文件描述符之间直接传递数据,从而避免了内核缓冲区和用户缓冲区之间的数据拷贝,称之为零拷贝。函数声明如下:
1 |
|
in_fd
:待读出内容的文件描述符,必须时支持类似mmap
函数的文件描述符,即它必须指向真实的文件,不能是 socket 和管道out_fd
:待写入内容的文件描述符,必须是一个 socketoffset
:指定从读入文件描述符的哪个位置开始读;空表示从默认起始位置开始读count
:指定传输的字节数- 调用成功返回传输的字节数,-1 表示出错
5. mmap 和 munmap
mmap
函数用于申请一段内存空间。munmap
函数则释放由 mmap
函数创建的这段内存空间。声明如下:
1 |
|
start
:允许用户使用某个特定地址作为内存的起始地址,设置为NULL
表示系统自动分配一个地址len
:指定内存端的长度prot
:设置内存端的访问权限,包括可读、可写、可执行和不能被访问flags
:控制内存段内容被修改后程序的行为fd
:被映射文件对应的文件描述符offset
:设置文件从何处开始映射
6. splice
splice
函数用于在两个文件描述符之间移动数据,也是零拷贝操作。函数声明如下:
1 |
|
fd_in
:待输入数据的文件描述符off_in
:如果fd_in
是管道文件描述符,则必须设置为NULL
;否则表示从输入数据流的何处开始读数据,为NULL
表示从输入流的当前偏移位置读入fd_out
:使用splice
时,fd_in
和fd_out
必须至少有一个为管道文件描述符off_out
:和in
相同,不过表示写入数据流len
:表示移动数据的长度flags
:控制数据如何移动
7. tee
tee
函数用于在两个管道文件描述符之间复制数据,也是零拷贝操作。它不消耗数据,因此源文件描述符上的数据仍然可以用于后续的读操作。函数声明如下:
1 |
|
函数参数含义与 splice
相同,但是 fd_in
和
fd_out
都必须是管道文件描述符。
8. fcntl
fcntl
(file
control)函数提供了对文件描述符的各种控制操作。另外一个能够控制文件描述符属性和行为的系统调用是
ioctl
,能够比 fcntl
执行更多的控制。fcntl
函数声明如下:
1 |
|
fd
:被操作的文件描述符cmd
:指定执行何种类型的操作arg
:可选参数
网络编程中,fcntl
函数常用于将文件描述符设置未非阻塞的:
1 |
|