При write
нужно рассмотреть только два случая:
- Если произойдет сбой, результатом будет -1 и установлено
errno
.
- Если это удается, результат равен 0 или больше, и
errno
не установлено.
Нет других случаев для рассмотрения, если вы не заинтересованы в исторических реализациях Unix (см .: Является ли возвращаемое значение 0 из write (2) в C ошибкой? ).
Причина, по которой write
может возвращать 0, заключается в том, что входной буфер может быть пустым.
Тем не менее, справочная страница вызова C write
примерно описывает errno
, может также быть установленным, но не указанным, если мы напишем буфер нулевой длины без объяснения каких-либо подробностей.
Все это означает, что возможна ошибка записи 0-длины. Если это не удалось, он возвращает -1 и устанавливает errno
. Если это удается, он возвращает 0 и не устанавливает errno
. Это то же самое поведение для любой другой записи, это только упомянуто на странице руководства, потому что люди могут найти удивительным, что запись 0 длины могла потерпеть неудачу.
Каково состояние errno
, если write
вызов возвращает 0 для файла, неблокирующего сокета или блокирующего сокета?
В этом случае errno
не установлено, поскольку write
не удалось. Это произойдет, только если входной буфер имеет нулевые байты.
Когда и как write
вызов с возвратом 0 и errno
не равен 0?
Этого не происходит. Либо errno
установлено, и возвращаемое значение равно -1, либо errno
не установлено, а возвращаемое значение равно 0 или больше.
Каков статус errno
, если write
звонок возвращается положительный? Будет ли это отрицательно?
Значение errno
не будет установлено. Он будет иметь то же значение, что и до вызова write
.
Есть ли другие системные вызовы, которые могут столкнуться с такой же ситуацией?
Как правило, системные вызовы либо возвращают ошибку , либо , они завершаются успешно. Они не будут делать смесь обоих. Посмотрите на раздел «Возвращаемое значение» на других справочных страницах, и вы увидите, что они в основном совпадают с write
.
Код
Этот код безопасен.
func writeAll(fd int, buffer []byte) bool {
length := len(buffer)
for length > 0 {
written, err := syscall.Write(fd, buffer)
if err != nil { // here
return false
}
length -= written
buffer = buffer[written:]
}
return true
}
Обратите внимание, что это немного избыточно, мы можем просто сделать это:
func writeAll(fd int, buf []byte) bool {
for len(buf) > 0 {
n, err := syscall.Write(fd, buf)
if err != nil {
return false
}
buf = buf[n:]
}
return true
}
Записка о С
Технически, write
- это и системный вызов, и функция C (по крайней мере, во многих системах). Однако функция C - это просто заглушка, которая вызывает системный вызов. Go не вызывает эту заглушку, она вызывает системный вызов напрямую, что означает, что C здесь не задействован (ну, пока вы не попадете в ядро).
Страница man показывает соглашения о вызовах и поведение заглушки C, write
. Go решает скопировать это поведение в свою заглушку, syscall.Write
. Реальный системный вызов имеет только интерфейс на языке ассемблера.