我有一个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集合,因为套接字几乎总是准备好写入,除了这里,所以选择器会立即返回。