在系统调用的手册页写入(2) –
ssize_t write(int fd, const void *buf, size_t count);
它说以下内容:
返回值
- 用于parsing参数GNU风格的库?
- 如何在Mac OS X上执行Raw IO? (即相当于Linux的O_DIRECT标志)
- 有没有一种方法来定位进程的哪一部分使用大部分内存,只查看生成的核心文件?
- 预计2.6.16和2.6.26内核版本之间的“kernel too old”错误
- C ++ Boost ASIO简单周期性定时器?
成功时,将返回写入的字节数(零表示什么都没有写入)。 出错时,返回-1,并适当地
errno
。 如果计数为零且文件描述符引用常规文件,则可能返回0,或者可能检测到错误。 对于一个特殊的文件,结果是不可移植的。
我认为这意味着返回0意味着没有任何东西被写出来,无论出于任何原因。
然而,当处理一个TCP套接字的文件描述符时,UNP中的Stevens将返回值0视为一个致命错误(这是由另一个在短期内调用exit(1)
函数封装的):
ssize_t /* Write "n" bytes to a descriptor. */ writen(int fd, const void *vptr, size_t n) { size_t nleft; ssize_t nwritten; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ( (nwritten = write(fd, ptr, nleft)) <= 0) { if (nwritten < 0 && errno == EINTR) nwritten = 0; /* and call write() again */ else return(-1); /* error */ } nleft -= nwritten; ptr += nwritten; } return(n); }
如果errno
表明写入调用被接收信号的进程中断,他只会将0作为合法返回值。
为什么?
史蒂文斯可能会这样做,以赶上旧的执行write()行为有所不同。 例如,Single Unix Spec说( http://www.opengroup.org/onlinepubs/000095399/functions/write.html )
如果IEEE Std 1003.1-2001的这一卷需要返回-1,并且将errno设置为[EAGAIN],则大多数历史实现将返回零
另外,在这里只是有些迂腐,如果你不写入套接字,我会检查,以确保缓冲区的长度(第一个例子中的“计数”)实际上是正确计算。 在Stevens的例子中,如果缓冲区长度为0,你甚至不会执行write()调用。
这将确保代码不会无限旋转,即使文件描述符不是TCP套接字或意外的非阻塞标志有效。 在某些系统上,如果没有数据可以被阻塞地写入,某些传统的非阻塞模式(例如O_NDELAY
)会导致write()
返回0(没有设置errno
),至少对于某些类型的文件描述符。 (POSIX标准的O_NONBLOCK
在这种情况下使用了一个错误返回。)而一些系统上的一些非阻塞模式适用于底层对象(比如socket,fifo)而不是文件描述符,所以甚至可以被启用另一个进程为同一个对象打开文件描述符。 在这种情况下,代码可以保护自己免受旋转的影响,因为它不能用于非阻塞模式。
如你的手册页所述,0的返回值对于特殊文件是“不可移植的”。 套接字是特殊文件,所以结果可能意味着不同的东西。
通常,对于套接字,read()或write()中的0字节值表示套接字已关闭,接收到0后,后续调用将返回-1,并带有错误代码。