Пример: функция str_echo, использующая стандартный ввод-вывод

Пример: функция str_echo, использующая стандартный ввод-вывод

Сейчас мы модифицируем наш эхо-сервер TCP (см. листинг 5.2) для использования стандартного ввода-вывода вместо функций readline и writen. В листинге 14.6 представлена версия нашей функции str_echo, использующая стандартный ввод-вывод. (С этой версией связана проблема, которую мы вскоре опишем.)

Листинг 14.6. Функция str_echo, переписанная с использованием стандартного ввода-вывода

//advio/str_echo_stdiо02.с

 1 #include "unp.h"

 2 void

 3 str_echo(int sockfd)

 4 {

 5  char line[MAXLINE];

 6  FILE *fpin, *fpout;

 7  fpin = Fdopen(sockfd, "r");

 8  fpout = Fdopen(sockfd, "w");

 9  while (Fgets(line, MAXLINE, fpin) != NULL)

10  Fputs(line, fpout);

11 }

Преобразование дескриптора в поток ввода и поток вывода

7-10 Функцией fdopen создаются два стандартных потока ввода-вывода: один для ввода и другой для вывода. Вызовы функций readline и writen заменены вызовами функций fgets и fputs.

Если мы запустим наш сервер с этой версией функции str_echo и затем запустим наш клиент, мы увидим следующее:

hpux % tcpcli02 206.168.112.96

hello, world мы набираем эту строку, но не получаем отражения

and hi       и на эту строку нет ответа

hello??      и на эту строку нет ответа

^D           наш символ конца файла

hello, world затем выводятся три отраженные строки

and hi

hello??

Здесь возникает проблема буферизации, поскольку сервер ничего не отражает, пока мы не введем наш символ конца файла. Выполняются следующие шаги:

? Мы набираем первую строку ввода, и она отправляется серверу.

? Сервер читает строку с помощью функции fgets и отражает ее с помощью функции fputs.

? Но стандартный поток ввода-вывода сервера полностью буферизован стандартной библиотекой ввода-вывода. Это значит, что библиотека копирует отраженную строку в свой стандартный буфер ввода-вывода для этого потока, но не выдает содержимое буфера в дескриптор, поскольку буфер не заполнен.

? Мы набираем вторую строку ввода, и она отправляется серверу.

? Сервер читает строку с помощью функции fgets и отражает ее с помощью функции fputs.

? Снова стандартная библиотека ввода-вывода сервера только копирует строку в свой буфер, но не выдает содержимое буфера в дескриптор, поскольку он не заполнен.

? По тому же сценарию вводится третья строка.

? Мы набираем наш символ конца файла, и функция str_cli (см. листинг 6.2) вызывает функцию shutdown, посылая серверу сегмент FIN.

? TCP сервера получает сегмент FIN, который читает функция fgets, в результате чего функция fgets возвращает пустой указатель.

? Функция str_echo возвращает серверу функцию main (см. листинг 5.9), и дочерний процесс завершается при вызове функции exit.

? Библиотечная функция exit языка С вызывает стандартную функцию очистки ввода-вывода [110, с. 162-164], и буфер вывода, который был частично заполнен нашими вызовами функции fputs, теперь выводит скопившиеся в нем данные.

? Дочерний процесс сервера завершается, в результате чего закрывается его присоединенный сокет, клиенту отсылается сегмент FIN и заканчивается последовательность завершения соединения TCP.

? Наша функция str_cli получает и выводит три отраженных строки.

? Затем функция str_cli получает символ конца файла на своем сокете, и клиент завершает свою работу.

Проблема здесь заключается в том, что буферизация на стороне сервера выполняется автоматически стандартной библиотекой ввода-вывода. Существует три типа буферизации, выполняемой стандартной библиотекой ввода-вывода.

1. Полная буферизация (fully buffered) означает, что ввод-вывод имеет место, только когда буфер заполнен, процесс явно вызывает функцию fflush или процесс завершается посредством вызова функции exit. Обычный размер стандартного буфера ввода-вывода — 8192 байта.

2. Буферизация по строкам (line buffered) означает, что ввод-вывод имеет место, только когда встречается символ перевода строки, процесс вызывает функцию fflush или процесс завершается вызовом функции exit.

3. Отсутствие буферизации (unbuffered) означает, что ввод-вывод имеет место каждый раз, когда вызывается функция стандартного ввода-вывода.

Большинство реализаций Unix стандартной библиотеки ввода-вывода используют следующие правила:

? Стандартный поток ошибок никогда не буферизуется.

? Стандартные потоки ввода и вывода буферизованы полностью, если они не подключены к терминальному устройству, в противном случае они буферизуются по строкам.

? Все остальные потоки тоже буферизованы полностью, если они не подключены к терминалу, в случае чего они буферизованы по строкам.

Поскольку сокет не является терминальным устройством, проблема, отмеченная с нашей функцией str_echo в листинге 14.6, заключается в том, что поток вывода (fpot) полностью буферизован. Есть два решения: мы можем сделать поток вывода буферизованным по строкам при помощи вызова функции setvbuf либо заставить каждую отраженную строку выводиться при помощи вызова функции fflush после каждого вызова функции fputs. Применение любого из этих изменений скорректирует поведение нашей функции str_echo. На практике оба варианта чреваты ошибками и могут плохо взаимодействовать с алгоритмом Нагла. В большинстве случаев оптимальным решением будет отказаться от использования стандартной библиотеки ввода-вывода для сокетов и работать с буферами, а не со строками (см. раздел 3.9). Использование стандартных функций ввода-вывода имеет смысл в тех случаях, когда потенциальный выигрыш перевешивает затруднения.

ПРИМЕЧАНИЕ

Будьте осторожны — некоторые реализации стандартной библиотеки ввода-вывода все еще вызывают проблемы при работе с дескрипторами, большими 255. Эта проблема может возникнуть с сетевыми серверами, обрабатывающими множество дескрипторов. Проверьте определение структуры FILE в вашем заголовочном файле <stdio.h>, чтобы увидеть, к какому типу переменных относится дескриптор.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Ввод/Вывод

Из книги Давайте создадим компилятор! автора Креншоу Джек


5.4. Стандартный ввод/вывод

Из книги Linux для пользователя автора Костромин Виктор Алексеевич

5.4. Стандартный ввод/вывод 5.4.1. Потоки ввода-вывода Когда программа запускается на выполнение, в ее распоряжение предоставляются три потока (или канала): • стандартный ввод (standard input или stdin). По этому каналу данные передаются программе; • стандартный вывод (standard output или


Ввод/вывод

Из книги Microsoft Visual C++ и MFC. Программирование для Windows 95 и Windows NT автора Фролов Александр Вячеславович

Ввод/вывод Как вы знаете, операторы << и >> выполняют сдвиг числового значения влево и вправо на опеределенное число бит. В программах, приведенных в нашей книге, эти операторы также используются для ввода информации с клавиатуры и вывода на экран.Если с левой стороны


Ввод и вывод

Из книги Основы объектно-ориентированного программирования автора Мейер Бертран

Ввод и вывод Два класса библиотеки KERNEL обеспечивают основные средства ввода и вывода: FILE и STD_FILES.Среди операций, определенных для объекта f типа FILE, есть следующие:create f.make ("name") -- Связывает f с файлом по имени name.f.open_write -- Открытие f для записиf.open_read -- Открытие f для


14.1.4. Стандартный ввод и вывод

Из книги Язык программирования Си для персонального компьютера автора Бочков C. О.

14.1.4. Стандартный ввод и вывод В главе 10 мы видели, как работают методы IO.popen и IO.pipe, но существует еще небольшая библиотека, которая иногда бывает удобна.В библиотеке Open3.rb есть метод popen3, который возвращает массив из трех объектов IO. Они соответствуют стандартному вводу,


Ввод и вывод

Из книги Linux программирование в примерах автора Роббинс Арнольд

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


4.4. Ввод и вывод

Из книги Программирование для Linux. Профессиональный подход автора Митчелл Марк

4.4. Ввод и вывод Все операции Linux по вводу/выводу осуществляются посредством дескрипторов файлов. Данный раздел знакомит с дескрипторами файлов, описывает, как их получать и освобождать, и объясняет, как выполнять с их помощью


2.1.4. Стандартный ввод-вывод

Из книги Основы программирования на Java автора Сухов С. А.

2.1.4. Стандартный ввод-вывод В стандартной библиотеке языка С определены готовые потоки ввода и вывода (stdin и stdout соответственно). Они используются функциями scanf(), printf() и целым рядом других библиотечных функций. Согласно идеологии UNIX, стандартные потоки можно


11. ввод/вывод

Из книги UNIX: разработка сетевых приложений автора Стивенс Уильям Ричард


5.3. Эхо-сервер TCP: функция str_echo

Из книги QT 4: программирование GUI на С++ автора Бланшет Жасмин

5.3. Эхо-сервер TCP: функция str_echo Функция str_echo, показанная в листинге 5.2, выполняет серверную обработку запроса клиента: считывание строк от клиента и отражение их обратно клиенту.Листинг 5.2. Функция str_echo: отраженные строки на сокете//lib/str_echo.c 1 #include "unp.h" 2 void 3 str_echo(int sockfd) 4 { 5 


14.8. Сокеты и стандартный ввод-вывод

Из книги Идеальный программист. Как стать профессионалом разработки ПО автора Мартин Роберт С.

14.8. Сокеты и стандартный ввод-вывод Во всех наших примерах мы применяли то, что иногда называется вводом-выводом Unix, вызывали функции read и write и их разновидности (recv, send и т.д.). Эти функции работают с дескрипторами и обычно реализуются как системные вызовы внутри ядра


21.8 Функция dg_cli, использующая многоадресную передачу

Из книги автора

21.8 Функция dg_cli, использующая многоадресную передачу Мы изменяем нашу функцию dg_cli, показанную в листинге 20.1, просто удаляя вызов функции setsockopt. Как мы сказали ранее, для отправки дейтаграмм многоадресной передачи не нужно устанавливать ни одного параметра сокета


Глава 12. Ввод—вывод

Из книги автора

Глава 12. Ввод—вывод Почти в каждом приложении приходится читать или записывать файлы или выполнять другие операции ввода—вывода. Qt обеспечивает великолепную поддержку ввода—вывода при помощи QIODevice — мощной абстракции «устройств», способных читать и записывать


Ввод и вывод

Из книги автора

Ввод и вывод Также мне кажется очень важным, чтобы мои результаты подпитывались соответствующим «вводом». Написание программного кода – творческая работа. Обычно мои творческие способности в наибольшей степени проявляются тогда, когда я сталкиваюсь с творческим