Чтение онлайн

на главную

Жанры

UNIX: разработка сетевых приложений
Шрифт:

2 ssize_t

3 readline(int fd, void *vptr, size_t maxlen)

4 {

5 ssize_t n, rc;

6 char c, *ptr;

7 ptr = vptr;

8 for (n = 1; n < maxlen; n++) {

9 again:

10 if ((rc = read(fd, &c, 1)) == 1) {

11 *ptr++ = c;

12 if (c == '\n')

13 break; /*
записан символ новой строки, как в fgets */

14 } else if (rc == 0) {

15 if (n == 1)

16 return (0); /* EOF, данные не считаны */

17 else

18 break; /* EOF, некоторые данные были считаны */

19 } else {

20 if (errno == EINTR)

21 goto again;

22 return (-1); /* ошибка, errno задается функцией read */

23 }

24 }

25 *ptr = 0; /* завершаем нулем, как в fgets */

26 return (n);

27 }

Если функция чтения или записи (

read
или
write
) возвращает ошибку, то наши функции проверяют, не совпадает ли код ошибки с EINTR (прерывание системного вызова сигналом, см. раздел 5.9). В этом случае прерванная функция вызывается повторно. Мы обрабатываем ошибку в этой функции, чтобы не заставлять процесс снова вызвать
read
или
write
, поскольку целью наших функций является предотвращение обработки нехватки данных вызывающим процессом.

В разделе 14.3 мы покажем, что вызов функции

recv
с флагом
MSG_WAITALL
позволяет обойтись без использования отдельной функции
readn
.

Заметим, что наша функция

readline
вызывает системную функцию
read
один раз для каждого байта данных. Это очень неэффективно, поэтому мы и написали в примечании «Ужасно медленно!». Возникает соблазн обратиться к стандартной библиотеке ввода-вывода (
stdio
). Об этом мы поговорим через некоторое время в разделе 14.8, но учтите, что это может привести к определенным проблемам. Буферизация, предоставляемая
stdio
, решает проблемы с производительностью, но при этом создает множество логистических сложностей, которые в свою очередь порождают скрытые ошибки в приложении. Дело в том, что состояние буферов
stdio
недоступно процессу. Рассмотрим, например, строчный протокол взаимодействия клиента и сервера, причем такой, что могут существовать разные независимые реализации клиентов и серверов (достаточно типичное явление; например, множество веб-браузеров и веб-серверов были разработаны независимо в соответствии со спецификацией HTTP). Хороший стиль программирования заключается в том, что эти программы должны не только ожидать от своих собеседников соблюдения того же протокола, но и контролировать трафик на возможность получения непредвиденного трафика. Подобные нарушения протокола должны рассматриваться как ошибки, чтобы программисты имели возможность находить и устранять неполадки в коде, а также обнаруживать попытки взлома систем. Обработка некорректного трафика должна давать приложению возможность продолжать работу. Буферизация
stdio
мешает достижению перечисленных целей, поскольку приложение не может проверить наличие непредвиденных (некорректных) данных в буферах
stdio
в любой конкретный момент.

Существует множество

сетевых протоколов, основанных на использовании строк текста: SMTP, HTTP, FTP, finger. Поэтому соблазн работать со строками будет терзать вас достаточно часто. Наш совет: мыслить в терминах буферов, а не строк. Пишите код таким образом, чтобы считывать содержимое буфера, а не отдельные строки. Если же ожидается получение строки, ее всегда можно поискать в считанном буфере.

В листинге 3.12 приведена более быстрая версия функции

readline
, использующая свой собственный буфер (а не буферизацию
stdio
). Основное достоинство этого буфера состоит в его открытости, благодаря чему вызывающий процесс всегда знает, какие именно данные уже приняты. Несмотря на это, использование
readline
все равно может вызвать проблемы, как мы увидим в разделе 6.3. Системные функции типа
select
ничего не знают о внутреннем буфере
readline
, поэтому неаккуратно написанная программа с легкостью может очутиться в состоянии ожидания в вызове
select
, при том, что данные уже будут находиться в буферах
readline
. По этой причине сочетание вызовов
readn
и
readline
не будет работать так, как этого хотелось бы, пока функция
readn
не будет модифицирована с учетом наличия внутреннего буфера.

Листинг 3.12. Улучшенная версия функции readline

//lib/readline.c

1 #include "unp.h"

2 static int read_cnt;

3 static char *read_ptr;

4 static char read_buf[MAXLINE];

5 static ssize_t

6 my_read(int fd, char *ptr)

7 {

8 if (read_cnt <= 0) {

9 again:

10 if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {

11 if (errno == EINTR)

12 goto again;

13 return(-1);

14 } else if (read_cnt == 0)

15 return(0);

16 read_ptr = read_buf;

17 }

18 read_cnt--;

19 *ptr = *read_ptr++;

20 return(1);

21 }

22 ssize_t

23 readline(int fd, void *vptr, size_t maxlen)

24 {

25 ssize_t n, rc;

26 char c, *ptr;

27 ptr = vptr;

28 for (n = 1; n < maxlen; n++) {

29 if ((rc = my_read(fd, &c)) == 1) {

30 *ptr++ = c;

31 if (c== '\n')

32 break; /* Записан символ новой строки, как в fgets */

33 } else if (rc == 0) {

34 *ptr = 0;

35 return(n - 1); /* EOF, считано n-1 байт данных */

36 } else

Поделиться:
Популярные книги

Сердце Дракона. Том 19. Часть 1

Клеванский Кирилл Сергеевич
19. Сердце дракона
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
7.52
рейтинг книги
Сердце Дракона. Том 19. Часть 1

Последняя Арена 10

Греков Сергей
10. Последняя Арена
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Последняя Арена 10

Идеальный мир для Лекаря 21

Сапфир Олег
21. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 21

Звезда сомнительного счастья

Шах Ольга
Фантастика:
фэнтези
6.00
рейтинг книги
Звезда сомнительного счастья

Live-rpg. эволюция-4

Кронос Александр
4. Эволюция. Live-RPG
Фантастика:
боевая фантастика
7.92
рейтинг книги
Live-rpg. эволюция-4

Девятое правило дворянина

Герда Александр
9. Истинный дворянин
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Девятое правило дворянина

Муж на сдачу

Зика Натаэль
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Муж на сдачу

Para bellum

Ланцов Михаил Алексеевич
4. Фрунзе
Фантастика:
попаданцы
альтернативная история
6.60
рейтинг книги
Para bellum

Егерь

Астахов Евгений Евгеньевич
1. Сопряжение
Фантастика:
боевая фантастика
попаданцы
рпг
7.00
рейтинг книги
Егерь

Вечная Война. Книга VII

Винокуров Юрий
7. Вечная Война
Фантастика:
юмористическая фантастика
космическая фантастика
5.75
рейтинг книги
Вечная Война. Книга VII

Я снова не князь! Книга XVII

Дрейк Сириус
17. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я снова не князь! Книга XVII

Ваантан

Кораблев Родион
10. Другая сторона
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Ваантан

Идущий в тени 4

Амврелий Марк
4. Идущий в тени
Фантастика:
боевая фантастика
6.58
рейтинг книги
Идущий в тени 4

Мятежник

Прокофьев Роман Юрьевич
4. Стеллар
Фантастика:
боевая фантастика
7.39
рейтинг книги
Мятежник