
- •3. Возникают некоторые проблемы
- •2. Ввод-вывод сетевых данных и данных в файловой системе
- •3. Возникают некоторые проблемы
- •4. Абстракция сокетов
- •5. Отличие дескриптора сокета от дескриптора файла
- •6. Создание сокета
- •7. Параметры сокета
- •8. Семейства протоколов и адресов
- •9. Тип соединения
- •10. Выбор протокола
- •11. Процесс
- •12. Что такое дескриптор сокета?
- •14. Использование сокета в программе
- •15. Настройка сокета
- •15. Соединение сокета
- •16. Указание локального адреса (порта протокола)
- •17. Передача данных через сокет
- •18. Передача данных через соединенный сокет
- •19. Передача данных через не соединенный сокет
- •20. Прием данных через сокет
- •22. Сокеты и серверы
- •23. Функция listen
- •24. Функция accept
- •25. Процесс-сервер
- •26. Принципы проектирования параллельного сервера
- •28. Подводя итоги
26. Принципы проектирования параллельного сервера
Вам, может быть, непонятно, каким образом параллельный сервер одновременно выполняет запросы, поступившие на один и тот же порт протокола. Вы помните, что для сетевого соединения сокету необходимо иметь две конечные точки.
Конечные точки сетевого соединения определяют адреса взаимодействующих процессов. До тех пор пока сетевые процессы соединены с различными точками сетевого соединения, они могут работать на одном и том же порту протокола, не мешая друг другу. Сервер параллельной обработки создает новый процесс для каждого соединения. Другими словами, на сетевом компьютере постоянно работает одиночный главный сервер, ожидая запроса от любого процесса в сети. В другой момент времени, на том же компьютере по-прежнему работает главный сервер, а вместе с ним — множество подчиненных. Каждый подчиненный сервер работает с уникальным адресом конкретного, соединенного с ним процесса.
Например, сегмент TCP идентифицируется своим уникальным адресом. Когда сервер принимает сегмент TCP, он отправляет его на сокет, связанный именно с адресом сегмента. Если такого сокета не существует (что означает поступление запроса на новую сетевую службу), сервер передаст сегмент сокету, соединенному с любым адресом (wildcard address). Мы помним, что сокет, соединенный с любым адресом, принимает запросы на соединения, поступающие с любого сетевого адреса. Начиная с этого момента весь процесс повторяется. Другими словами, сокет главного процесса-сервера (прослушивающий запросы с любого сетевого адреса) порождает дочерний процесс-сервер, который, в свою очередь, и обрабатывает запрос.
Необходимо понимать, что сокет, прослушивающий любой сетевой адрес, не может иметь открытого соединения. Мы помним, что для установления сетевого соединения необходимо иметь пару конечных точек, каждая из которых должна обладать определенным адресом. Поскольку сокет главного процесса-сервера всегда прослушивает запросы с любого адреса, он в состоянии обработать только вновь поступивший запрос.
Существует другая функция, не показанная на рис. 4 и 5, — она довольно часто используется серверами и называется «select». Сложные программы-клиенты также могут использовать ее. Функция select позволяет одиночному Процессу следить за состоянием сразу нескольких сокетов. При вызове select указываются пять параметров. Первый параметр, количество сокетов (number of sockets), задает общее количество сокетов для наблюдения. Параметры readable-sockets, writeable-sockets и error-sockets являются битовыми масками, задающими тип сокетов. Приведенный ниже оператор демонстрирует, как можно вызвать функцию select:
result = select (number_of_sockets, readable_sockets, writeable_sockets, error_sockets, max_time);
Сокет для чтения (readable socket) содержит принятые данные, которые извлекаются программой при помощи стандартных вызовов recv или recvfrom. Сокет для записи (writable socket) — это сокет, установивший соединение. Через него программа может передавать данные, используя стандартные функции типа send или sendto. В случае сетевой ошибки, функция select обозначает сокет, в котором это произошло, как ошибочный (exception). Ситуация ошибки требует дальнейшей программной обработки. В любом случае select определяет состояние только тех сокетов, которые были отмечены в каждой битовой маске. Интерфейс сокетов использует битовые маски для определения набора сокетов, за которыми будет установлено наблюдение. При выходе в вызывающую программу select возвращает количество сокетов, готовых к операциям ввода-вывода. Для заданных, дескрипторов файлов функция select также изменяет их битовые маски.
Другими словами, вы указываете функции select за какими сокетами следить и какого рода информация о каждом из сокетов вас интересует. Функция select, в свою очередь, информирует вас о количестве сокетов, готовых для приема-передачи данных (чтения, записи и сообщений об ошибках). В дополнение select модифицирует битовые маски таким образом, что каждый сокет оказывается принадлежащим определенной категории. До того как вызвать функцию select, программа должна установить биты в маске так, чтобы они указывали на сокеты, информацию о которых необходимо получить. Функция select сбросит биты, указывающие на любой сокет, не готовый к определенной операции ввода-вывода. После завершения функции select прикладная программа может проанализировать содержимое битовой маски. Если бит, идентифицирующий определенный сокет, окажется установленным, это значит, что сокет готов к операции ввода-вывода (чтению, записи или сообщению об ошибке).
Можно написать программу так, что она будет изменять свое выполнение в зависимости от результатов вызова функции select. Предположим, мы спроектировали программу, создающую три сокета. Предположим, у нас есть одна процедура, обслуживающая операции чтения, другая процедура, осуществляющая запись, и третья, обрабатывающая ошибочные ситуации. Функция select может вызываться, чтобы одновременно получить информацию о состоянии всех трех сокетов. Предположим, что в результате вызова select программа узнает, что один сокет может считывать данные, второй может записывать, а третий содержит информацию об ошибке. В этом случае разумнее всего будет вызвать процедуру обработки ошибок. На самом деле, получив статус всех контролируемых сокетов, программа может выбрать то действие, которое наиболее разумно предпринять.