Поток против буфера

#c #io #buffer #bufferedinputstream

Вопрос:

там я новичок в С. В настоящее время я читаю Kamp;R. Там меня смутило содержащееся в нем определение текстовых потоков: «Текстовый поток-это последовательность символов, разделенных на новые строки;каждая строка состоит из 0 или более символов, за которыми следует символ новой строки». И, пытаясь узнать об этих потоках, я познакомился с новым термином, а именно с буфером.

Я просто знаю, что:

  • Непрерывный поток данных (байтов или символов) между устройствами ввода и вывода представляет
    собой ПОТОК .
  • Область временного хранения в основной памяти для временного хранения входных или выходных данных представляет собой БУФЕР.

Я не говорю, что я прав, но это моя основная идея на этих условиях.

Я хочу знать, что такое на самом деле буфер и поток и как эти 2 вещи(т. Е. поток и буфер) работают вместе на неабстрактном уровне реализации C.

Ответ №1:

У вас есть три потока в C, stdin , stdout , и stderr вы также можете думать о файлах , которые вы открыли, fopen например, как о потоке. stdin как правило, это клавиатура, stdout как правило, ваш монитор, stderr как правило, также и ваш монитор. Но это не обязательно так, это абстракции для аппаратного обеспечения.

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

Таким образом, в некотором смысле, думайте о буфере как о памяти, выделенной операционной системой, связанной с потоком, для хранения данных, полученных от аппаратного компонента. Например, когда вы печатаете на клавиатуре, вводимые вами символы не захватываются непосредственно вашей средой разработки, они перемещаются оттуда в буфер, а затем вы считываете буфер.

Вот почему, например, вам нужно нажать enter, прежде чем ваш код начнет взаимодействовать с тем, что вы набрали на клавиатуре, потому stdin что строка буферизована. Управление передается от вашей программы к операционной системе до тех пор, пока она не столкнется с чем-то, что отправляет управление обратно в вашу программу, в обычной ситуации это был бы символ новой строки.

Таким образом, в некотором смысле, думайте об этом так: поток-это устройство (клавиатура, монитор или файл на вашем жестком диске), буфер-это место, где хранятся данные, пока операционная система контролирует их, а затем вы взаимодействуете с буфером во время обработки данных.

Эта абстракция позволяет вам использовать все эти разные вещи общим способом, независимо от того, что они собой представляют, например: fgets(str, sizeof(str), STREAM) … поток может быть любым входным потоком, будь то он stdin или файл.

Делая еще один шаг вперед , вот почему новых программистов сбрасывают scanf за an int , за которым следует an fgets , потому scanf что считывает int из буфера, но оставляет n в буфере … затем вызов fgets считывает n то, что scanf там осталось, и новому программисту остается только гадать, почему они не смогли ввести какие-либо данные. Таким образом, ваше любопытство к потокам и буферам сослужит вам хорошую службу по мере продвижения вперед в изучении C.

Комментарии:

1. Эй @LEF, спасибо, чувак, твой ответ заставил меня наконец прийти к выводу. Это мне очень помогло!

2. Эй, не могли бы вы предложить мне книгу, которая поможет мне узнать более глубокие реализации C (то есть узнать, как это реальные абстракции работают за кулисами).

3. @UdayKiran все, что я когда-либо использовал, — это Язык программирования Си, в этой маленькой книжке целая жизнь обучения. Но иногда это слишком «высокий уровень», поэтому копайтесь в ядре Linux. Он написан на C, и, поскольку он с открытым исходным кодом, вы действительно можете посмотреть, как реализуются абстракции. Вы можете видеть, что происходит за кулисами fgets , например, когда вы звоните. Если вы ищете интересный проект, напишите настройку сервера / клиента чата, воспользуйтесь сетевым руководством Beej, оно поможет вам освоить программирование на Linux (и расширить ваши знания о потоках).

4. @UdayKiran с точки зрения серверной / клиентской программы, углубитесь в функцию выбора, вы даже можете написать небольшую игру или что-то в этом роде, используя функцию timer_fd ядра Linux, затем с точки зрения документации для изучения вы просто используете руководство программиста linux (справочные страницы) вместе с различными ресурсами в Интернете. Вы увидите, что stdin просто имплантирован как файловый дескриптор, и так далее, и тому подобное. Повеселиться.

5. @UdayKiran допустил опечатку в приведенном выше комментарии, и время для редактирования истекло, просто чтобы было ясно, что это timerfd, а не timer_fd

Ответ №2:

Определения не плохие, на самом деле очень хорошие. Вы могли бы добавить (с объектно-ориентированной точки зрения), что ПОТОК использует БУФЕР.

Использование БУФЕРА может потребоваться, например, по соображениям производительности, поскольку каждый системный вызов сопряжен с относительно высокой стоимостью.

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

Ответ №3:

Двумя общими абстракциями устройств ввода-вывода являются:

Потоки — передает переменное количество байтов по мере готовности устройства.

Блок — перенос записей фиксированного размера.

Буфер — это просто область памяти, в которой хранятся передаваемые данные.

Ответ №4:

На самом деле это довольно хорошие рабочие определения.

В практических терминах языка Си буфер-это массив (обычно типа char или unsigned char ), который используется для хранения данных либо в результате операции ввода, либо перед отправкой на вывод. Массив может быть объявлен как массив фиксированного размера, например

 char buffer[SOME_BUFFER_SIZE];
 

или динамически, используя

 char *buffer = malloc( SOME_BUFFER_SIZE * sizeof *buffer );
 

Преимущество использования динамической памяти заключается в том, что при необходимости размер буфера можно изменять; недостатком является то, что вам приходится управлять временем жизни этой памяти.

Для ввода/вывода текста вы обычно используете массивы char ; для двоичного ввода/вывода вы обычно используете массивы unsigned char .

Системы, взаимодействующие по сети, довольно часто отправляют данные «кусками» фиксированного размера, так что для передачи всех данных может потребоваться несколько операций чтения или записи. Подумайте о веб — сервере и браузере-сервер отправляет HTML в нескольких сообщениях, а браузер сохраняет промежуточный результат в буфере. Только после того, как все данные будут получены, браузер отобразит страницу:

 Received from Web server       Stored in browser's input buffer
------------------------       --------------------------------
HTTP/1.1 200 OK rn           <!DOCTYPE HTML><html
Content-length: 20rn
<!DOCTYPE HTML><html

HTTP/1.1 200 OK rn           <!DOCTYPE HTML><html><head><title>This i
Content-length: 20rn
><head><title>This i

HTTP/1.1 200 OK rn           <!DOCTYPE HTML><html><head><title>This i
Content-length: 20rn         s a test</title></he
s a test</title></he

HTTP/1.1 200 OK rn           <!DOCTYPE HTML><html><head><title>This i
Content-length: 20rn         s a test</title></head><body><p>Hello, W
ad><body><p>Hello, W

HTTP/1.1 200 OK rn           <!DOCTYPE HTML><html><head><title>This i
Content-length: 19             s a test</title></head><body><p>Hello, W
orld!</body></html>            orld!</body></html>
 

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