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-8 stdineof — это новый флаг, инициализируемый нулем. Пока этот флаг равен нулю, мы будем проверять готовность стандартного потока ввода к чтению с помощью функции 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 — версию, работающую с программными потоками.
Данный текст является ознакомительным фрагментом.