Возвращаемое значение 0 из write (2) в C является ошибкой? - PullRequest
13 голосов
/ 01 февраля 2010

В справочной странице для системного вызова write (2) -

ssize_t write(int fd, const void *buf, size_t count);

сказано следующее:

Возвращаемое значение

В случае успеха количество байтов записано возвращено (ноль указывает ничего не было написано). При ошибке -1 возвращается, и errno установлен соответственно. Если счет равен нулю и дескриптор файла относится к обычный файл, 0 может быть возвращен или ошибка может быть обнаружена. Для особого файл, результаты не переносимы.

Я бы интерпретировал это как означающее, что возвращение 0 просто означает, что ничего не было написано по любой произвольной причине.

Однако Стивенс в UNP обрабатывает возвращаемое значение 0 как фатальную ошибку при работе с файловым дескриптором, который является TCP-сокетом (это оборачивается другой функцией, которая вызывает 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);
}

Он рассматривает 0 как допустимое возвращаемое значение, только если errno указывает, что запрос на запись был прерван процессом, получающим сигнал.

Почему?

Ответы [ 4 ]

7 голосов
/ 01 февраля 2010

Стивенс, вероятно, делает это, чтобы поймать старые реализации write (), который вел себя по-другому. Например, Single Unix Spec говорит (http://www.opengroup.org/onlinepubs/000095399/functions/write.html)

Где этот том IEEE Std 1003.1-2001 требует, чтобы -1 был возвращен и для него было установлено значение [EAGAIN], большинство исторические реализации возвращают ноль

3 голосов
/ 01 февраля 2010

Это гарантирует, что код не будет вращаться бесконечно, даже если дескриптор файла не является сокетом TCP или действуют неожиданные неблокирующие флаги. В некоторых системах определенные устаревшие неблокирующие режимы (например, O_NDELAY) заставляют write() возвращать 0 (без установки errno), если никакие данные не могут быть записаны без блокировки, по крайней мере, для определенных типов файловых дескрипторов. (Стандарт POSIX O_NONBLOCK использует возврат ошибки для этого случая.) И некоторые неблокирующие режимы в некоторых системах применяются к базовому объекту (например, socket, fifo), а не к дескриптору файла, и поэтому могли бы даже быть включен другим процессом, имеющим открытый дескриптор файла для того же объекта. Код защищает себя от вращения в такой ситуации, просто рассматривая его как ошибку, поскольку он не предназначен для использования в неблокирующих режимах.

1 голос
/ 01 февраля 2010

Кроме того, и просто чтобы быть немного педантичным, если вы не пишете в сокет, я бы проверил, чтобы убедиться, что длина буфера ("count" в первом примере) действительно рассчитывается правильно. В примере Стивенса вы даже не выполняете вызов write (), если длина буфера равна 0.

0 голосов
/ 01 февраля 2010

Как сказано в вашей справочной странице, возвращаемое значение 0 не является переносимым для специальных файлов. Сокеты - это специальные файлы, поэтому результат может означать для них что-то другое.

Обычно для сокетов значение 0 байтов от read () или write () указывает на то, что сокет закрыт, и после получения 0 последующие вызовы вернут -1 с кодом ошибки.

...