70-散布读、聚集写

看到这个标题你可能会懵圈,没事,只是名字有点恐怖而已。在英文中,它们被称为 scatter read和 gather write.

1. 引例

看下面一段代码:

char buf1[10];
char buf2[20];
char buf3[15];

write(fd, buf1, 10);
write(fd, buf2, 20);
write(fd, buf3, 15);

上面这样的代码实际上很常见,不知道你是否还记得我们在讲解 TCP_NODELAY 套接字选项的时候,遇到过一种 write-write-read 的情形,和这个很类似。

接下来我想说的是,有没有一种办法,只执行一次 write 就可以把所有 buf 中的数据写入?最容易想到的就是将三个 buf 缓冲中的数据合并成一个 buf,一次写入。linux 为我们提供了另一个更加方便的函数——writev,它意为 write vector,即一次写入很多个 buf,比如可以这样:

writev(fd, buf1, 10, buf2, 20, buf3, 15);

当然啦,上面这种方法只是为了方便描述,实际上 writev 函数的参数是一个结构体数组。

writev 函数和 readv 函数原型:

ssize_t readv(int fd, const struct iovec *iov, int iovcnt);

ssize_t writev(int fd, const struct iovec *iov, int iovcnt);

这两个函数参数相同,下面只讲解 writev 函数的用法,readv 函数雷同。

2. writev 函数

  • 函数原型
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);

struct iovec {
  void  *iov_base;    /* 缓冲区地址 */
  size_t iov_len;     /* 要读写多少字节 */
};

writev 函数的第二个参数是一个 iovec 类型数组,第三个参数是数组的大小。

如果将第 1 节中的程序改为 writev 方式实现,应该像下面这样:

struct iovec iov[3];
iov[0].iov_base = buf1;
iov[0].iov_len = 10;

iov[1].iov_base = buf2;
iov[1].iov_len = 20;

iov[2].iov_base = buf3;
iov[2].iov_len = 15;

writev(fd, iov, 3);

是不是非常简单?writev 有一个好处是它的操作是原子的,意味着它在内部会将所有缓冲区中的数据一次性发送出去,对于 UDP 来说,它只产生一个 UDP 数据报。

3. writev 函数示例

下面这段程序,将 buf 缓冲中的下标为偶数位置数据写入文件 filename 中。

void write_routine() {
  int i, fd, nw;
  struct iovec iov[10];
  char buf[64];

  strcpy(buf, "abcdefghijklmnopqrstuvwxyz");

  for (i = 0; i < 10; ++i) {
    iov[i].iov_base = buf + 2*i;
    iov[i].iov_len = 1;
  }

  fd = open(filename, O_WRONLY | O_CREAT, 0666);
  if (fd < 0) ERR_EXIT("open");

  nw = writev(fd, iov, 10);
  if (nw < 0) ERR_EXIT("writev");
}

最后,文件 filename 中的内容是:

acegikmoqs

4. 程序运行结果

代码托管在 gitos 上,请使用下面的命令获取:

git clone https://git.oschina.net/ivan_allen/unp.git

如果你已经 clone 过这个代码了,请使用 git pull 更新一下。本节程序所使用的程序路径是 unp/program/advcio/readv_writev/rwv.cc.

程序 rwv 包含了 writev 和 readv 的例子,使用命令行参数控制。

  • readv 演示

readv 从文件 filename 中读取数据,并写入到 iovec 指定的缓冲区中。在此 demo 中,将数据定入到了 buf 缓冲区中下标为偶数的位置中。


这里写图片描述
图1 readv 演示结果

  • writev 演示

writev 函数示例和第 3 节中描述的一致。


这里写图片描述
图2 writev 函数演示

5. 总结

  • 掌握 writev 和 readv 函数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值