write()系统调用何时写入所有请求的缓冲区而不是仅执行部分写入?

时间:2009-03-29 06:04:38

标签: linux unix

如果我指望我的write()系统调用写入例如100字节,我总是将该write()调用放在一个循环中,该循环检查返回的长度是否是我预期发送的长度如果没有,它会碰撞缓冲区指针并减少写入量的长度。

所以我再一次这样做了,但是现在有了StackOverflow,我可以问你所有人是否知道我的写作会写出我要求的所有内容而不是给我一个部分写入?

补充评论:X-Istence的回复提醒我,我应该注意到文件描述符是阻塞的(即,不是非阻塞的)。我认为他建议阻塞文件描述符上的write()不会写入所有指定数据的唯一方法是write()被信号中断。这对我来说似乎至少具有直觉意义......

3 个答案:

答案 0 :(得分:5)

write可能会返回部分写入,尤其是使用套接字上的操作或内部缓冲区已满。好的方法是做以下事情:

while(size > 0 && (res=write(fd,buff,size))!=size) {
    if(res<0 && errno==EINTR) 
       continue;
    if(res < 0) {
        // real error processing
        break;
    }
    size-=res;
    buf+=res;
}

永远不要接受通常发生的事情......

注意:如果是完整磁盘,您将获得ENOSPC而不是部分写入。

答案 1 :(得分:4)

你需要检查errno以查看你的调用是否被中断,或者为什么write()提前返回,以及为什么它只写了一定数量的字节。

来自man 2 write

  

在对象(例如受流控制的套接字)上使用非阻塞I / O时,write()和writev()可以写入比请求的更少的字节;必须注意返回值,并且应尽可能重试操作的其余部分。

基本上,除非你写一个非阻塞套接字,否则唯一的另一个时间就是你被信号打断了。

  

[EINTR]信号在写入完成之前中断写入。

有关可以返回的内容以及何时返回的详细信息,请参阅man page中的“错误”部分。从那里你需要弄清楚错误是否严重到足以记录错误并退出,或者你是否可以继续手头的操作!

这一切都在书中讨论过:Advanced Unix Programming by Marc J. Rochkind,我已经在本书的帮助下编写了无数的程序,并且会在为类似OS的UNIX编程时提出建议。

答案 2 :(得分:-2)

写入应该没有任何理由永远写入部分缓冲区。我可以想到部分写入的可能原因是,如果你的磁盘空间不足,你正在写一个块设备的末尾,或者你正在写一个字符设备/其他类型的设备。

然而,盲目重写的计划可能不是那么好 - 检查错误,看看你是否应该先重试。