Книга: UNIX: разработка сетевых приложений
6.7. Функция str_cli (еще раз)
6.7. Функция str_cli (еще раз)
В листинге 6.2 представлена наша обновленная (и корректная) функция str_cli
. В этой версии используются функции select
и shutdown
. Первая уведомляет нас о том, когда сервер закрывает свой конец соединения, а вторая позволяет корректно обрабатывать пакетный ввод. Эта версия избавлена от ориентации на строки. Вместо этого она работает с буферами, что позволяет полностью избавиться от проблем, описанных в конце раздела 6.5.
Листинг 6.2. функция str_cli, использующая функцию select, которая корректно обрабатывает конец файла
//select/strcliselect02.c
1 #include "unp.h"
2 void
3 str_cli(FILE *fp, int sockfd)
4 {
5 int maxfdp1, stdineof;
6 fd_set rset;
7 char buf[MAXLINE];
8 int n;
9 stdineof = 0;
10 FD_ZERO(&rset);
11 for (;;) {
12 if (stdineof == 0)
13 FD_SET(fileno(fp), &rset);
14 FD_SET(sockfd, &rset);
15 maxfdp1 = max(fileno(fp), sockfd) + 1;
16 Select(maxfdp1, &rset, NULL, NULL, NULL);
17 if (FD_ISSET(sockfd, &rset)) { /* сокет готов для чтения */
18 if ((n = Read(sockfd, buf, MAXLINE)) == 0) {
19 if (stdineof == 1)
20 return; /* нормальное завершение */
21 else
22 err_quit("str_cli: server terminated prematurely");
23 }
24 Write(fileno(stdout), buf, n);
25 }
26 if (FD_ISSET(fileno(fp), &rset)) { /* есть данные на входе */
27 if ((n = Read(fileno(fp), buf, MAXLINE)) == 0) {
28 stdineof = 1;
29 Shutdown(sockfd, SHUT_WR); /* отправка сегмента FIN */
30 FD_CLR(fileno(fp), &rset);
31 continue;
32 }
33 Writen(sockfd, buf, n);
34 }
35 }
36 }
5-8stdineof
— это новый флаг, инициализируемый нулем. Пока этот флаг равен нулю, мы будем проверять готовность стандартного потока ввода к чтению с помощью функции select
.
16-24
Если мы считываем на сокете признак конца файла, когда нам уже встретился ранее признак конца файла в стандартном потоке ввода, это является нормальным завершением и функция возвращает управление. Но если конец файла в стандартном потоке ввода еще не встречался, это означает, что процесс сервера завершился преждевременно. В новой версии мы вызываем функции read
и write
и работаем с буферами, а не со строками, благодаря чему функция select
действует именно так, как мы рассчитывали.
25-33
Когда нам встречается признак конца файла на стандартном устройстве ввода, наш новый флаг stdineof
устанавливается в единицу и мы вызываем функцию shutdown
со вторым аргументом SHUT_WR
для отправки сегмента FIN.
Если мы измерим время работы нашего клиента TCP, использующего функцию str_cli
, показанную в листинге 6.2, с тем же файлом из 2000 строк, это время составит 12,3 с, что почти в 30 раз быстрее, чем при использовании версии этой функции, работающей в режиме остановки и ожидания.
Мы еще не завершили написание нашей функции str_cli
: в разделе 15.2 мы разработаем ее версию с использованием неблокируемого ввода-вывода, а в разделе 23.3 — версию, работающую с программными потоками.
- От исключительной полезности к стратегическому ценообразованию
- Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ
- Решетка «упразднить – снизить – повысить – создать»
- Миграция между различными версиями InterBase
- 4.7. Игровые разминки и упражнения-энергизаторы
- Совместимость клиентов и серверов различных версий
- Выбор стратегии ценообразования
- Преобразование XML в реляционную базу данных
- 2.1.3. Функция getopt_long()
- 1.1.4. Еще немного терминов
- Класс StreamReader
- Размер страницы базы данных