2015-01-31 4 views
2

В man страницах Linux о write() он заявил, что в случае EINTR или EAGAINwrite() вернется -1. При выполнении read() можно повторить попытку, если такие ошибки встречаются. Что делать в таких ситуациях при выполнении write()?как писать в сокет правильно

ответ

1

Насколько я знаю, способ обработки таких случаев включает в себя завершение вызова write() внутри функции, которая проверяет возвращаемое значение, а также переменную errno.

EAGAIN Случаи, как и EINTR указывают на ситуации, когда write() был неудачным из-за какой-то сигнал прервал его или O_NONBLOCK был установлен, но write() будет блокировать. Это означает, что вы можете повторить попытку write(), проверив состояние errno.

Я не уверен,, однако, если это гарантирует, что write() будет в конечном итоге добиться успеха, если вы настаиваете (и, конечно, если вы не получаете никакой иной errno статус).

Вы могли бы сделать что-то вроде

ssize_t insist_write(int fd, const void * buff, size_t cnt) 
{ 
    ssize_t ret; 
    size_t original_cnt = cnt; 
    while (cnt > 0) 
    { 
     ret = write(fd, buff, cnt); 
     if (ret < 0) 
     { 
      // EINTR for interrupted writes, EAGAIN - EWOULDBLOCK for file/socket 
      // blocking case (see man page) 
      if ((errno != EINTR) && (errno != EAGAIN) && (errno != EWOULDBLOCK)) 
       return ret; 
      else 
       ret = 0; 
     } 
     // update buff and remaining bytes to write 
     buff += ret; 
     cnt -= ret; 
    } 
    return original_cnt; 
} 

Я также видел код, где выше случае обрабатываемый делают

if (ret < 0) { return ret; } 

вместо того, что я написал, это означает, что такие случаи будут обрабатываться на на основе каждого приложения (в одном из таких примеров указывается максимальное количество попыток write() перед возвратом -1).

-1

Это правда, что вы можете обернуть звонки write(), проверив для EINTR или EAGAIN. Простой цикл попробовать write() снова в тех случаях, предлагается в this вопрос, и может хорошо работать:

+0

Автор писал: «Я читаю страницы' man', и я понимаю, что если 'write()' fail с ошибкой 'EAGAIN' или' EINTR', я должен выполнить 'write()' again_ "no , не обязательно. Попробуйте еще раз. Это зависит от реализации, а страницы 'man' никогда не говорили ничего подобного. Его понимание и, следовательно, описание его вопроса неверны. – Barracuda

1

Вы можете повторить попытку в случае EINTR.

Вы можете получить только EAGAIN/EWOULDBLOCK если вы в не- режим блокировки, и в этих случаях нецелесообразно просто повторять в цикле. Вы должны select() до тех пор, пока сокет не станет доступен для записи, и затем повторите попытку. Это может произойти только тогда, когда одноранговый узел что-то читает, поэтому не рекомендуется записывать циклы процессора на отправляющем конце.

Смежные вопросы