Почему ограничения на стандартные потоки ввода / вывода C, которые взаимодействуют с сокетами? - PullRequest
0 голосов
/ 17 октября 2018

В разделе 10.9 книги CSAPP говорится, что есть два ограничения на стандартные потоки ввода-вывода, которые плохо взаимодействуют с ограничениями на сокеты.

Ограничение 1: Функции ввода, следующие за функциями вывода.Функция ввода не может следовать за функцией вывода без промежуточного вызова fflush, fseek, fsetpos или rewind.Функция fflush очищает буфер, связанный с потоком.Последние три функции используют функцию поиска ввода / вывода Unix для сброса текущей позиции файла.

Ограничение 2: Функции вывода следуют за функциями ввода.Функция вывода не может следовать за функцией ввода без промежуточного вызова fseek, fsetpos или rewind, если только функция ввода не встречает конец файла.

Но я не могу понять, почему наложены ограничения,Итак, мой вопрос: какие факторы приводят к двум ограничениям?

Также говорится, что «использование функции lseek в сокете запрещено», но как это возможно fseek, fsetpos и rewind используйте lseek для сброса текущей позиции файла, если она истинна?

Здесь есть похожий вопрос здесь , но мой вопрос отличается от этого.

Ответы [ 2 ]

0 голосов
/ 17 октября 2018

Когда написано «Функция ввода не может следовать за функцией вывода без промежуточного вызова fflush, fseek, fsetpos или rewind», это означает, что если вы этого не сделаете, она может работать не так, как вы ожидаете.Но они в основном говорят о вводе-выводе в / из обычных файлов.

Если у вас есть поток FILE *, подключенный к сокету, и вы хотите переключаться между записью и чтением, я быожидайте, что он будет работать нормально, если вы позвоните fflush при переключении с записи на чтение.Я не ожидал бы, что при переключении с чтения на запись будет необходимо что-либо вызывать.

(При работе с файлами необходим вызов к fseek или одному из его родственников, чтобы обновить позицию файлаправильно, но потоки не имеют позиции файла для обновления.)

0 голосов
/ 17 октября 2018

Функции stdio предназначены для ввода и вывода буферизованного файла .Сокет это не файл, а сокет.Он даже не имеет файловой позиции, и требования к буферу совершенно не похожи на обычные файлы - сокеты могут иметь независимые буферы ввода и вывода, а ввод / вывод stdio файла невозможен!

Проблема в том, что file input и file output совместно используют такую ​​же позицию файла, и операционная система может иметь (и действительно будет иметь в Unix) позицию файла, отличную от позиции файлаиз-за буферизации в C будет.

Следовательно, из обоснования C99

Изменение направления ввода / вывода в файле обновления допускается только после успешного fsetpos,fseek, rewind или fflush, поскольку именно эти функции обеспечивают сброс буфера ввода-вывода.

Обратите внимание, что все это относится только к открытым файламс + - с файлами, открытыми в любых других стандартных режимах, невозможно смешать ввод и вывод.

Поскольку в стандарте C требуется, чтобы при переключении from input to output on FILE * одна из функций fsetpos, rewind или fseek, которая по сути вызывает lseek, должна быть успешной (учтите, чтоfflush сбрасывает вывод, а не входной буфер!) Перед попыткой выполнения функции вывода ... однако сокет не может быть найден, и поэтому lseek всегда будет сбой - это означает, что вы не можете использовать FILE *, который был открыт как для чтения, так и для записи, обертывая сокет для фактически чтения и записи в сокет.


Возможно использоватьfdopen чтобы открыть FILE * с потоковыми сокетами, если вам действительно необходимо: просто откройте 2 файлов - один "rb" для ввода и другой с "wb" для вывода.

...