2

我有一个基于 TCP 的套接字,我正在 C++03 程序中写入该套接字。在某些情况下,我从 write() 得到零返回结果。write(2) 手册页部分说明:

成功时,返回写入的字节数(零表示未写入任何内容)。出错时,返回 -1,并适当设置 errno。

那么,零真的意味着没有错误,我应该再次调用 write 直到我已经写完所有内容?换句话说,我是否应该像对待部分写入一样处理零,其中写入的字节数少于count我传递给写入的字节数,然后继续尝试直到达到count写入的总字节数?

我想确保我不会陷入无限循环,写入连续返回零并且永远不会取得进展。我是否应该先调用 select() 以确保文件描述符在调用 write 之前准备好?我在文件描述符上启用了阻塞。

4

2 回答 2

1

如果您提供零长度,则A write()orsend()在阻塞模式下只能返回零。这几乎可以肯定是您的编程错误。

唯一的例外是如果您使用零长度写入来证明本地 TCP 堆栈以查看是否存在任何未决错误,例如 ECONNRESET。

在非阻塞模式下,零长度写入意味着套接字发送缓冲区已满。当你得到这个时,你应该开始在该套接字上选择一个 writefd,并在套接字变为可写时重试写入。如果成功,请停止选择它作为 writefd。您通常根本不应该使用 writefd 集,因为除了这里之外,套接字几乎总是准备好写入,因此选择器会立即返回。

于 2013-05-19T00:03:04.350 回答
1

尽管从理论上讲,它最终可能会通过或出错,但我会针对无限循环建立一些安全性,以防万一。

调用select等待硬件可能会起作用(这肯定比立即再次循环尝试要好,这几乎肯定会浪费一些 CPU 时间 - 多少取决于很多事情),但这是一个TOCTOU问题 - 中的其他一些程序您的系统可能在您之前到达那里,并且(再次)在您到达时填满了可用于传输的系统内存write

所以,我会按照这些思路做一些事情:

int write_zero_count = 0; 

while(not_all_written)
{
  int res;
  res = select(...);
  ... check if we can write, etc ... 
  res = write(...);
  if (res == 0)
  {
     write_zero_count++;
     if (write_zero_count > max_zero_writes)
     {
        error("Got many writes that sent zero bytes, not good");
        .... do other stuff to log and recover from error or exit? ...
     } 
  }
  else
  {
      write_zero_count = 0;
  }
}
于 2013-05-18T15:18:10.280 回答