Что означает чтение / запись в дескрипторе файла сокета? И почему обычные файлы не беспокоятся об этом?
Так как я недавно начал изучать libev, в io_watcher
что я не совсем понимаю. Насколько мне известно, есть параметр в системном программировании Linux:
O_ASYNC
Сигнал (по умолчанию SIGIO) будет сгенерирован, когда указанный файл станет доступным для чтения или записи. Этот флаг доступен только для терминалов и сокетов, но не для обычных файлов.
Итак, поскольку обычный файл не будет беспокоиться о возможности чтения / записи, что на самом деле означает чтение / запись в программировании сокетов? И какую меру предприняло ядро, чтобы выяснить, читается ли дескриптор файла сокета?
Учитывая философию "все в файле", каждый дескриптор сокета с другим номером дескриптора на самом деле указывает на один и тот же файл? Если да, могу ли я считать, что проблема с читаемостью / записью вызвана синхронизацией?
ОК, кажется, я задал глупый вопрос. Что я действительно имею в виду, так это то, что как сокет, так и обычный файл читаются и записываются через дескриптор файла, так почему дескриптор сокета получил концепцию чтения / записи, а обычный файл - нет. Так как EJP сказал мне, что это потому, что у буфера и каждого дескриптора есть своя собственная пара буферов, вот мой вывод: концепция для чтения / записи предназначена для буферов, если буфер пустой, он не читаемый, хотя он полон, он не записывается. Доступные для чтения и записи не имеют ничего общего с синхронизацией, и поскольку обычный файл не имеет буфера, он всегда доступен для чтения и записи.
И есть еще вопросы: при получении буфера приема, этот буфер не то же самое в int recv(SOCKET socket, char FAR* buf, int len, int flags);
, право?
1 ответ
Этот вопрос специально рассматривается в Unix Network Programming, Volume 1: The Sockets Networking API (3-е издание) [W. Ричард Стивенс, Билл Феннер, Эндрю М. Рудофф] ( см. Здесь. Я добавлю некоторые незначительные правки для улучшения читаемости):
При каких условиях готов дескриптор?
[...] Условия, которые вызывают
select
вернуть "готово" для сокетов [есть]:1 Сокет готов к чтению, если выполняется любое из следующих четырех условий:
- Количество байтов данных в приемном буфере сокета больше или равно текущему размеру метки нижнего уровня для приемного буфера сокета. Операция чтения в сокете не блокируется и возвращает значение больше 0 (т. Е. Данные, которые готовы к чтению). [...]
- Чтение половины соединения закрыто (т. Е. TCP-соединение, получившее FIN). Операция чтения в сокете не блокируется и возвращает 0 (т. Е. EOF).
- Сокет является слушающим сокетом, и число выполненных соединений отлично от нуля. [...]
- Ожидается ошибка сокета. Операция чтения в сокете не блокируется и возвращает ошибку (–1) с
errno
установить конкретное состояние ошибки. [...]2 Сокет готов к записи, если выполняется любое из следующих четырех условий:
- Число байтов доступного пространства в буфере отправки сокета больше или равно текущему размеру метки низкого уровня для буфера отправки сокета и либо: (i) сокет подключен, либо (ii) сокет делает не требует подключения (например, UDP). Это означает, что если мы установим сокет в неблокирующее состояние, операция записи не будет блокироваться и будет возвращать положительное значение (например, количество байтов, принятых транспортным уровнем). [...]
- Половина записи соединения закрыта. Операция записи в сокет сгенерирует
SIGPIPE
,- Сокет, использующий неблокирующее соединение, завершил соединение или соединение не удалось.
- Ожидается ошибка сокета. Операция записи в сокет не блокируется и возвращает ошибку (–1) с
errno
установить конкретное состояние ошибки. [...]3 Сокет имеет условие исключения, ожидающее, если для сокета есть данные вне диапазона, или сокет все еще находится во внеполосной метке.
[Заметки:]
Наши определения "читабельный" и "доступный для записи" взяты непосредственно из ядра
soreadable
а такжеsowriteable
макросы на стр. 530–531 протокола TCPv2. Точно так же наше определение "условия исключения" для сокета происходит отsoo_select
функционировать на этих же страницах.Обратите внимание, что при возникновении ошибки в сокете она помечается как читаемая и записываемая
select
,Цель получения и отправки нижних отметок состоит в том, чтобы дать приложению контроль над тем, сколько данных должно быть доступно для чтения или сколько места должно быть доступно для записи, прежде чем select вернет состояние для чтения или записи. Например, если мы знаем, что нашему приложению не нужно ничего продуктивного, если не присутствует хотя бы 64 байта данных, мы можем установить для знака низкого уровня приема значение 64, чтобы предотвратить выбор, который разбудит нас, если готово менее 64 байтов для чтение.
- Пока нижняя отметка отправки для сокета UDP меньше размера буфера отправки (который всегда должен быть отношением по умолчанию), сокет UDP всегда доступен для записи, так как соединение не требуется.
Связанное чтение из той же книги: буфер отправки сокета TCP и буфер отправки сокета UDP (псевдо)
Читаемый означает, что в буфере приема сокета есть данные или FIN.
Запись означает, что в буфере отправки сокета есть место.
Файлы не имеют буфера отправки или получения сокетов.
Принимая во внимание философию "все в файле"
Что это за философия?
каждый дескриптор сокета с другим номером дескриптора на самом деле указывает на один и тот же файл?
Какой файл? Почему они указывают на то же самое? Вопрос не имеет смысла.
Меня смущает одно: когда создается сокет, дескриптор фактически указывает на буферы приема и отправки сокета.
Он "указывает" на многие вещи: адрес источника, целевой адрес, порт источника, целевую точку, пару буферов, набор счетчиков и таймеров,...
не файл представляет сетевое оборудование.
Не существует такого понятия, как "файл, представляющий сетевое оборудование", если вы не говорите о записи драйвера устройства в /dev/...
, что едва уместно. TCP-сокет является конечной точкой соединения. Это относится к этому соединению, к TCP, к исходным и целевым адресам и портам,...