概述
分散/聚集 I/O是一种可以在单次系统调用中对多个缓冲区输入输出的方法,可以把多个缓冲区的数据写到单个数据流,也可以把单个数据流读到多个缓冲区中。其命名的原因在于数据会被分散到指定缓冲区向量,或者从指定缓冲区向量中聚集数据。这种输入输出方法也称为向量 I/O(vector I/O)。与之不同,标准读写系统调用(read,write)可以称为线性I/O(linear I/O)。
与线性 I/O 相比,分散/聚集 I/O 有如下几个优势:
编码模式更自然
如果数据本身是分段的(比如预定义的结构体的变量),向量 I/O 提供了直观的数据处理方式。
效率更高
单个向量 I/O 操作可以取代多个线性 I/O 操作。
性能更好
除了减少了发起的系统调用次数,通过内部优化,向量 I/O 可以比线性 I/O 提供更好的性能。
支持原子性
和多个线性 I/O 操作不同,一个进程可以执行单个向量 I/O 操作,避免了和其他进程交叉操作的风险。
readv() 和 writev()
Linux实现了POSIX 1003.1-2001中定义的一组实现分散/聚集 I/O机制的系统调用。该实现满足了上面所述的所有特性。
readv() 函数从文件描述符 fd 中读取 count 个段 (segment) (一个段即一个 iovec 结构体)到参数 iov 所指定的缓冲区中:
#include <sys/uio.h>
ssize_t readv (int fd,
const struct iovec *iov,
int count)
write() 函数从参数 iov 指定的缓冲区中读取 count 个段的数据,并写入 fd 中:
#include <sys/uio.h>
ssize_t writev(int fd,
const struct iovec *iov,
int count)
除了同时操作多个缓冲区外,readv() 函数和 writev() 函数的功能分别和 read(),write() 的功能一致。
每个 iovec 结构体描述一个独立的,物理不连续的缓冲区,我们称其为段(segment):
#include <sys/uio.h>
struct iovec {
void *iov_base;/* pointer to start of buffer */
size_t iov_len;/* size of buffer in bytes */
};
一组段的集合称为向量(vector)。每个段描述了内存中所要读写的缓冲区的地址和长度。readv() 函数在处理下个缓冲区之前,会填满当前缓冲区的 iov_len 个字节。write() 函数在处理下个缓冲区之前,会把当前缓冲区所有 iov_len 个字节数据输出,这两个函数都会顺序处理向量中的段,从 iov[0] 开始,接着是 iov[1],一直到 iov[count - 1] 。
返回值
优化count值
例子
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <sys/uio.h> int main() { struct iovec iov[3]; ssize_t nr; int fd, i; char *buf[] = { "Just because you can do it, doesn't mean that you have to.\n", "Just because you can do it, doesn't mean that you have to.\n", "Just because you can do it, doesn't mean that you have to.\n" }; fd = open("c++.txt", O_WRONLY | O_CREAT | O_TRUNC); if (fd == -1) { perror("open"); } /* fill out therr iovec structures */ for (i = 0; i < 3; ++i) { iov[i].iov_base = buf[i]; iov[i].iov_len = strlen(buf[i]) + 1; } /* write a single call, write them all out */ nr = writev(fd, iov, 3); if (nr != -1) { perror("writev"); return 1; } if (close(fd)) { perror("close"); } return 0; }readv() 例子:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/uio.h> int main() { char foo[48], bar[50], baz[49]; struct iovec iov[3]; ssize_t nr; int fd, i; fd = open("c++.txt", O_RDONLY); if (fd == -1) { perror("open"); return 1; } /* set up our iovec structrues */ iov[0].iov_base = foo; iov[0].iov_len = sizeof(foo); iov[1].iov_base = bar; iov[1].iov_len = sizeof(bar); iov[2].iov_base = baz; iov[2].iov_len = sizeof(baz); /* read into the structures with a single call */ nr = readv(fd, iov, 3); if (nr == -1) { perror("readv"); return 1; } for (i = 0; i < 3; ++i) { printf("%d: %s", i, (char*) iov[i].iov_base); } if (close(fd)) { perror("close"); return 1; } return 0; }