Будет ли системный вызов write() блокировать дальнейшую работу до тех пор, пока не будет задействовано read(), или наоборот?
Написано как часть клиент-сервера TCP/IP:
Сервер:
write(nfds,data1,sizeof(data1));
usleep(1000);
write(nfds,data2,sizeof(data2));
Клиент:
read(fds,s,sizeof(s));
printf("%s",s);
read(fds,s,sizeof(s));
printf("%s",s);
Без usleep(1000)
между двумя вызовами write()
, клиент печатает data1 дважды. Почему это?
Фон:
Я делаю программу клиент-сервер, где сервер должен отправлять два последовательных фрагмента информации после их получения через сеть (сокет); nfds
дескриптор файла мы получаем accept()
, На стороне клиента мы получаем эту информацию через read
; Вот fds
это дескриптор файла, полученный через socket()
,
Моя проблема в том, что когда я НЕ использую usleep(1000)
между write()
функции, клиент просто печатает информацию, представленную data1 дважды, вместо печати data1 и затем data2. Когда я положил в usleep()
все в порядке. ПОЧЕМУ это происходит? Является write()
блокирование операции до тех пор, пока буфер не будет прочитан или не будет read()
блокировать операцию, пока информация не будет записана в буфер? Или я полностью со страницы?
1 ответ
Вы делаете несколько ложных предположений. В TCP нет ничего, что гарантировало бы, что одна отправка равна одной полученной. На обоих концах много буферизации, и есть преднамеренные задержки при отправке, чтобы объединить пакеты (алгоритм Nagle). Когда вы звоните read()
, или же recv()
и друзья, вам нужно сохранить результат в переменной и проверить его для каждого из следующих случаев:
- -1: ошибка: изучить / войти / распечатать
errno
, или жеstrerror()
, или позвоните по телефонуperror()
и в большинстве случаев закройте сокет и выйдите из цикла чтения. - 0: конец потока; владелец закрыл соединение; закройте сокет и выйдите из цикла чтения.
- положительное значение, но меньше, чем вы ожидали: продолжайте читать и накапливать данные, пока у вас не будет все, что вам нужно.
- положительное значение больше ожидаемого: обработайте данные, которые вы ожидали, и сохраните остаток для следующего раза.
- именно то, что вы ожидали: обработать данные, отбросить все и повторить. Это не простой случай, и он редок, но это единственный случай, для которого вы сейчас программируете.
Не добавляйте сны в сетевой код. Это не решает проблемы, оно только задерживает их.