写(2)返回零意味着什么,我最终会取得进展吗(非零结果)

What does write(2) return of zero mean and will I eventually make progress (non-zero result)?

本文关键字:结果 意味着 返回 什么      更新时间:2023-10-16

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

成功时,返回写入的字节数(0表示没有写入)。如果出现错误,则返回-1,并适当设置errno。

那么,0真的意味着没有错误,我应该再次调用write,直到所有内容都写完吗?换句话说,我是否应该只处理一个0,就像我已经为部分写入所做的那样,其中写入的字节数小于我传递给写入的count,并继续尝试,直到我达到写入的count字节总数?

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

虽然从理论上讲,它可能最终通过或得到一个错误,但我将构建一些针对无限循环的安全性,以防万一。

调用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;
  }
}

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

唯一的例外是,如果你使用零长度写来证明本地TCP堆栈,看看是否有任何挂起的错误,如ECONNRESET。

在非阻塞模式下,零长度写入表示socket发送缓冲区已满。当您得到这个时,您应该开始选择该套接字作为writefd,并在套接字变为可写时重试写操作。如果成功,停止将其作为已写文件进行选择。通常不应该使用writefd集合,因为套接字几乎总是准备好写入,除了这里,所以选择器会立即返回。