Пример однопотокового сервера службы ECHO
Для пояснения описанных выше принципов и иллюстрации того, как один поток может применяться для обеспечения параллельной работы, воспользуемся следующим примером. Рассмотрим файл TCPmechod.c, который содержит код сервера, реализующего службу ECHO.
/* Файл TCPmechod.c - главная процедура echo */ tinclude tinclude tinclude tinclude tinclude tinclude tinclude tdefine QLEN 32 /* Максимальная длина очереди соединений */ tdefine BUFSIZE 4096 extern int errno; int errexit(const char *format, ...); int passiveTCP(const char *service, int qlen); int echo(int fd);
Выполнение потока этого сервера, как и выполнение ведущего потока сервера в параллельной реализации, начинается с открытия пассивного сокета в общепринятый порт. В этом примере используется системная функция getdtablesize для определения максимального числа дескрипторов, а затем применяются макрокоманды FD_ZER0 и FDJ3ET для создания битового вектора, соответствующего дескрипторам сокетов, которые должны контролироваться функцией select. Затем сервер входит в бесконечный цикл, в котором он вызывает функцию select для ожидания готовности к работе одного или нескольких дескрипторов.
Если готов дескриптор ведущего сокета, сервер вызывает функцию accept для получения нового соединения. Он добавляет дескриптор нового соединения к управляемому им набору и снова переходит в состояние ожидания активизации следующих дескрипторов. Если же готов дескриптор ведомого сокета, сервер вызывает процедуру echo, в которой вызывается функция read для получения данных из соединения и функция write для отправки их назад клиенту. Если один из дескрипторов ведомого сокета сообщает о получении признака конца файла, сервер закрывает дескриптор и использует макрокоманду FD_CLR для удаления его из набора дескрипторов, используемых функцией select.
13.6. Резюме
Выполнение обработки данных в параллельных серверах часто активизируется в результате поступления самих данных, а не с помощью механизма квантования времени базовой операционной системы. В тех случаях, если предоставляемая служба требует небольшого объема обработки, для такого же эффективного обслуживания соединений с многочисленными клиентами, как и в варианте на основе нескольких потоков или процессов, может использоваться один поток выполнения, в котором осуществляется асинхронный ввод/вывод.
В однопотоковой реализации один поток выполнения берет на себя обязанности одного ведущего и нескольких ведомых потоков. Если готов к работе ведущий сокет, единственный поток сервера вызывает функцию accept для получения нового соединения. А если готов любой другой сокет, поток сервера принимает запрос и передает ответ. В приведенном примере с сервером службы ECHO показано, как обеспечить параллельную обработку в одном потоке, а также проиллюстрированы тонкости программирования. Клиническая диета. Купить смеси для зондового питания. Лечебное питание.
Поскольку функция select перед возвратом управления очищает все дескрипторы, не доступные для чтения или записи, в этом коде набор активных дескрипторов копируется в переменную rfds при каждом проходе по циклу while.
Материал для дальнейшего изучения
Качественная спецификация протокола отличается тем, что она не ограничивает возможности реализации. Например, в однопотоковом сервере, описанном в настоящей главе, осуществлен протокол службы ECHO, который определен в документе [120], а в главах 11 и 12 приведены примеры альтернативных реализаций, созданных на основе той же спецификации протокола. В этих реализациях, соответственно, используются несколько процессов (каждый из которых содержит один поток выполнения) или один многопотоковый процесс.
Упражнения
- Проведите эксперимент, который доказывает, что сервер службы ECHO, приведенный в данном примере, обеспечивает параллельное обслуживание соединений.
- Имеет ли смысл использовать реализацию, описанную в данной главе, для создания службы DAYTIME? Объясните ваш ответ.
- Прочитайте оперативную документацию, чтобы узнать, как именно представлены дескрипторы в списке, передаваемом функцией select. Напишите макрокоманды FDJ3ET и FD_CLR.
- Сравните производительность сервера, в котором используется один поток, и сервера, в котором используется несколько процессов на компьютере с несколькими процессорами. При каких обстоятельствах версия с одним потоком будет работать лучше (или одинаково) по сравнению с версией, в которой используется несколько процессов?
- Предположим, что к серверу, который рассматривается в качестве примера в данной главе, одновременно обращается много клиентов (скажем, 100). Объясните, что может наблюдать каждый из этих клиентов.
- Может ли сервер, в котором используется один поток выполнения, когда-либо лишить одного клиента доступа к службе, снова и снова обслуживая запросы другого? Может ли сервер, в котором используется несколько потоков, или сервер, в котором используется несколько однопотоковых процессов, когда-либо отказать в обслуживании какому-либо клиенту? Объясните ваш ответ.