gpt4 book ai didi

write(2) 能否返回写入的 0 个字节*,如果返回怎么办?

转载 作者:IT王子 更新时间:2023-10-29 00:19:46 26 4
gpt4 key购买 nike

我想实现一个合适的 write(2)循环接受一个缓冲区并不断调用 write 直到整个缓冲区被写入。

我想基本的方法是这样的:

/** write len bytes of buf to fd, returns 0 on success */
int write_fully(int fd, char *buf, size_t len) {
while (len > 0) {
ssize_t written = write(fd, buf, len);
if (written < 0) {
// some kind of error, probably should try again if its EINTR?
return written;
}
buf += written;
len -= written;
}
return 0;
}

...但这提出了一个问题,即 write() 是否可以有效地返回写入的 0 字节以及在这种情况下该怎么做。如果这种情况持续存在,上面的代码只会在 write 调用上热旋转,这似乎是个坏主意。只要返回不是零的,您就在取得进展。

write 的手册页有点模棱两可。它说,例如:

On success, the number of bytes written is returned (zero indicates nothing was written).

这似乎表明在某些场景下是可能的。只有一种这样的场景被明确指出:

If count is zero and fd refers to a regular file, then write() may return a failure status if one of the errors below is detected. If no errors are detected, or error detection is not performed, 0 will be returned without causing any other effect. If count is zero and fd refers to a file other than a regular file, the results are not specified.

上面避免了这种情况,因为我从不使用 len == 0 调用 write。还有很多其他情况无法写入任何内容,但通常它们都有与之关联的特定错误代码。

文件本身将根据命令行中给出的路径/名称打开。所以它通常是一个常规文件,但用户当然可以传递诸如管道之类的东西,进行输入重定向,传递诸如 /dev/stdout 之类的特殊设备等等。我至少可以控制 open 调用,并且 O_NONBLOCK 标志不会传递给 open。我无法合理地检查所有文件系统、所有特殊设备的行为(即使我可以,也会添加更多),所以我想知道如何以合理和通用的方式处理这个问题.


* ... 对于非零缓冲区大小。

最佳答案

TL;DR 总结

除非您不顾一切地调用未指定的行为,否则您不会从 write() 返回零结果,除非您尝试写入零字节(问题中的代码避免这样做)。

POSIX 表示:

我相信 write() 的 POSIX 规范涵盖了这个问题。

The write() function shall attempt to write nbyte bytes from the buffer pointed to by buf to the file associated with the open file descriptor, fildes.

Before any action described below is taken, and if nbyte is zero and the file is a regular file, the write() function may detect and return errors as described below. In the absence of errors, or if error detection is not performed, the write() function shall return zero and have no other results. If nbyte is zero and the file is not a regular file, the results are unspecified.

这说明如果您请求写入零字节,您可能会得到零返回值,但有一些警告 — 它必须是一个常规文件,如果像 EBADF 这样的错误是您可能会得到一个错误检测到,并且未指定如果文件描述符不引用常规文件会发生什么。

If a write() requests that more bytes be written than there is room for (for example, [XSI]⌦ the file size limit of the process or ⌫ the physical end of a medium), only as many bytes as there is room for shall be written. For example, suppose there is space for 20 bytes more in a file before reaching a limit. A write of 512 bytes will return 20. The next write of a non-zero number of bytes would give a failure return (except as noted below).

[XSI]⌦ If the request would cause the file size to exceed the soft file size limit for the process and there is no room for any bytes to be written, the request shall fail and the implementation shall generate the SIGXFSZ signal for the thread. ⌫

If write() is interrupted by a signal before it writes any data, it shall return -1 with errno set to [EINTR].

If write() is interrupted by a signal after it successfully writes some data, it shall return the number of bytes written.

If the value of nbyte is greater than {SSIZE_MAX}, the result is implementation-defined.

这些规则并没有真正允许返回 0(尽管学究可能会说太大的 nbyte 值可能被定义为返回 0)。

When attempting to write to a file descriptor (other than a pipe or FIFO) that supports non-blocking writes and cannot accept the data immediately:

  • If the O_NONBLOCK flag is clear, write() shall block the calling thread until the data can be accepted.

  • If the O_NONBLOCK flag is set, write() shall not block the thread. If some data can be written without blocking the thread, write() shall write what it can and return the number of bytes written. Otherwise, it shall return -1 and set errno to [EAGAIN].

…details for obscure file types — a number of them with unspecified behaviour…

Return value

Upon successful completion, these functions shall return the number of bytes actually written to the file associated with fildes. This number shall never be greater than byte. Otherwise, -1 shall be returned and errno set to indicate the error.

因此,由于您的代码避免尝试写入零字节,只要 len 不大于 {SSIZE_MAX},并且只要您不写入模糊的文件类型(如共享内存对象或类型化内存)对象)你不应该看到 write() 返回零。


POSIX 原理说:

稍后在 write() 的 POSIX 页面的基本原理部分中,有以下信息:

Where this volume of POSIX.1-2008 requires -1 to be returned and errno set to [EAGAIN], most historical implementations return zero (with the O_NDELAY flag set, which is the historical predecessor of O_NONBLOCK, but is not itself in this volume of POSIX.1-2008). The error indications in this volume of POSIX.1-2008 were chosen so that an application can distinguish these cases from end-of-file. While write() cannot receive an indication of end-of-file, read() can, and the two functions have similar return values. Also, some existing systems (for example, Eighth Edition) permit a write of zero bytes to mean that the reader should get an end-of-file indication; for those systems, a return value of zero from write() indicates a successful write of an end-of-file indication.

因此,尽管 POSIX(即使不是全部,也很大程度上)排除了从 write() 返回零的可能性,但相关系统上的现有技术确实使 write() 返回零。

关于write(2) 能否返回写入的 0 个字节*,如果返回怎么办?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41904221/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com