Эффективное программирование TCP-IP

       

Архитектура с одним соединением


Следует заметить, что ничего не изменится, если на рис. 3.3 вместо TTY-coединения будет написано TCP-соединение. Поэтому та же техника может приме­няться (и часто применяется) для работы с сетевыми соединениями. Кроме того, использование потоков вместо процессов почти не сказывается на ситуации, изоб­раженной на рисунке, поэтому этот метод пригоден и для многопоточной среды.

Правда, есть одна трудность. Если речь идет о TTY-соединении, то ошибки при операции записи возвращаются самим вызовом write, тогда как в случае TCP ошибка, скорее всего, будет возвращена последующей операцией чтения (совет 15). В много процессной архитектуре процессу-читателю трудно уведомить процесс-писатель об ошибке. В частности, если приложение на другом конце завершается, то об этом узнает читатель, который должен как-то известить писателя.

Немного изменим точку зрения и представим себе приложение, которое принимает сообщения от внешней системы и посылает их назад по TCP-соединению. Сообщения передаются и принимаются асинхронно, то есть не для каждого входного сообщения генерируется ответ, и не каждое выходное сообщение посылается в ответ на входное. Допустим также, что сообщения нужно переформатировать на

Рис. 3.4. Приложение, обменивающиеся сообщениями по TCP-соединению

входе или выходе из приложения. Тогда представленная на рис. 3.4 архитектура многопроцессного приложения оказывается вполне разумной.

На этом рисунке процесс xin читает данные от внешней системы, накапливает их в очереди сообщений, переформатирует и передает главному процессу обработки сообщений. Аналогично процесс xout приводит выходное сообщение к формату, требуемому внешней системой, и записывает данные в TCP-соединение. Главный процесс mp обрабатывает отформатированные входные сообщения и генерирует выходные сообщения. Оставляем неспецифицированным механизм межпроцессного взаимодействия (IPC) между тремя процессами. Это может быть конвейер, разделяемая память, очереди сообщений или еще что-то. Подробнее все возможности рассмотрены в книге [Stevens 1999]. В качестве реального примера такого рода приложения можно было бы привести шлюз, через который передаются сообщения между системами. Причем одна из систем работает по протоколу TCP, а другая - по какому-либо иному протоколу.


Если обобщить этот пример, учитывая дополнительные внешние системы с иными требованиями к формату сообщений, то становится ясно, насколько гибкие возможности предоставляет описанный метод. Для каждого внешнего хоста имеется свой набор коммуникационных процессов, работающих только с его сообщениями. Такая система концептуально проста, позволяет вносить изменения, относящиеся к одному из внешних хостов, не затрагивая других, и легко конфи­гурируется для заданного набора внешних хостов - достаточно лишь запустить свои коммуникационные процессы для каждого хоста.

Однако при этом остается нерешенной вышеупомянутая проблема: процесс-писатель не может получить сообщение об ошибке после операции записи. А иногда у приложения должна быть точная информация о том, что внешняя система действительно получила сообщение, и необходимо организовать протокол под­тверждений по типу того, что обсуждался в совете 9. Это означает, что нужно либо создать отдельный коммуникационный канал между процессами xin и xout, либо xin должен посылать информацию об успешном получении и об ошибках процессу mp, который, в свою очередь, переправляет их процессу xout. To и другое усложняет взаимодействие процессов.

Можно, конечно, отказаться от многопроцессной архитектуры и оставить всего один процесс, добавив select для мультиплексирования сообщений. Однако при этом приходится жертвовать гибкостью и концептуальной простотой.

Далее в этом разделе рассмотрим альтернативную архитектуру, при которой сохраняется гибкость, свойственная схеме на рис. 3.4, но каждый процесс самостоятельно следит за своим TCP-соединением.


Содержание раздела