【问题标题】:How to deal if writev only write part of the data?writev 只写入部分数据怎么处理?
【发布时间】:2017-07-21 01:55:04
【问题描述】:

我的数据是自然分段的,并且来自不同的来源,所以我使用 writev 函数如下。

char *buf0 = "short string\n";
struct bar *my_bar;
my_baz = get_my_baz();
iov[0].iov_base = buf0;
iov[0].iov_len = strlen(buf0);
iov[1].iov_base = my_bar;
iov[1].iov_len = sizeof (struct bar);
bytes_written = writev (sockfd, iov, 3);

我想发送我所有的数据。如果writev一次只写入部分数据怎么办,例如:

bytes_written = 1;

如何继续发送剩余数据? 在write函数中,我们可以这样做enter link description here,那么writev呢?

【问题讨论】:

  • 文档中的重要说明:“readv()writev() 执行的数据传输是原子的:writev() 写入的数据作为单个块写入不会与其他进程中写入的输出混合”(注意:此保证不是 POSIX 的一部分,Linux 以外的操作系统可能只写入部分数据)
  • @BenVoight 这并不排除在非阻塞模式下的短写。
  • @EJP:当然可以,短写甚至自动恢复操作都不会保留原子性。
  • @BenVoigt 您的报价涉及“执行的数据传输”。 IE。 实际上写了什么。它没有说明所有用户提供的数据都会被写入而不管非阻塞模式,套接字发送缓冲区中没有空间等。这将违反非阻塞模式语义。
  • @EJP:从atomic的基本定义开始。原子传输完全有可能具有非阻塞语义,或者整个块适合缓冲区,或者调用失败而不写入任何内容,返回 -1 并将 errno 设置为 EWOULDBLOCK。

标签: linux sockets


【解决方案1】:
  1. iov[0].iov_base 增加bytes_written
  2. iov[0].iov_len 递减bytes_written
  3. 注意下溢,即如果 iov[0].iov_len 变为负数,请记住它,将其设置为零,然后以与 (1) 和 (2) 相同的方式将差异传播到 iov[1],依此类推,直到关闭.

但是,如果您处于阻塞模式,这不是问题,因为永远不会出现短写入的情况。

【讨论】:

  • 你回答的意思是在writev函数中数据是按照iov[0]到iov[n]的顺序一个一个写入的?
  • @zwfars 这就是文档所说的。你肯定读过吗?
  • 但是 writev 中的 iov 是 const: ssize_t writev(int __fd, const struct iovec* __iov, int __count); , 不能修改 iov_base 和 iov_len。
  • @Ted const 表示writev() 不能修改它,而不是你不能。
猜你喜欢
  • 1970-01-01
  • 2012-05-05
  • 2016-09-07
  • 1970-01-01
  • 2021-02-06
  • 1970-01-01
  • 2016-02-10
  • 2011-07-01
  • 2012-11-17
相关资源
最近更新 更多