Техника менеджера ресурса вводит дополнительный уровень разрешения имен, который реализуется через менеджер процессов procnto
(как это происходит, подробно и на примерах описывается в [1]). Происходящее при выполнении POSIX-оператора:
int fd = open("/net/host/dev/srv", O_RDONLY);
по внутреннему содержанию в точности соответствует тому, что происходит в процессе организации обмена сообщениями при выполнении:
int coid = ConnectAttach(node, pid, chid, 0, 0);
и может даже при определенных обстоятельствах возвратить то же значение и уж по крайней мере всегда возвращает значение той же природы, хотя мы и говорим по привычке в первом случае «файловый дескриптор», а во втором - «идентификатор соединения». Здесь отчетливо видна подмена адресной триады node
, pid
и chid
именем пути /net/host/dev/srv
.
Модель адресации менеджера ресурса в QNX, конечно, намного более универсальна, гибка и мобильна, нежели модель прямого обмена сообщениями. Например, можно написать сервер, который при запуске воспринимал бы полное имя, под которым он будет регистрироваться в пространстве имен, например (пусть даже некоторые варианты и сомнительны в своей осмысленности):
# server -n /dev/srv
# server -n /proc/srv
# server -n /fs/srv
Можно запустить несколько экземпляров такого сервера, возможно модифицированных использованием других ключей запуска:
# server -n /dev/srv1
# server -n /dev/srv2
Наконец, можно сделать это не только на своем локальном узле сети, но и на других сетевых узлах:
# on -f host1 server -n /dev/srv1
# on -f host1 server -n /dev/srv2
# on -f host2 server -n /dev/srv1
# on -f host2 server -n /dev/srv1
Теперь, если наш клиент выполнен так, что позволяет при запуске указать имя сервера, который он должен использовать, мы можем применить такой клиент для работы с самыми различными экземплярами серверов, где бы они ни находились в сети, например:
# client -s /dev/srv1
# client -s /net/host2/dev/srv1
Полный исходный код такой реализации будет показан в примере, к рассмотрению которого мы перейдем после завершения этого раздела.
В чем еще состоит различие, которое можно отнести к категории гибкости механизмов?
В краткой схеме, показанной кодом предыдущего раздела, вызовом:
MsgSend(coid, &bufou, sizeof(bufou), &bufin, sizeof(bufin));
может быть послано сообщение произвольной(в пределах абсолютных ограничений) длины ( sizeof(bufou)
). Это сообщение (с информацией о его фактической длине) будет принято сервером, который в свою очередь может ответить сообщением произвольной длины, которое и будет доставлено клиенту в ответ на оператор MsgSend()
.
При обмене с менеджером ресурсов, в силу необходимости приведения клиентских запросов в «прокрустово ложе» POSIX, картина принципиально другая: каждый запрос может оперировать только с данными той длины, которая предопределена стандартом.
1. Команды группы read()
могут передать в направлении сервера только код команды, уточненный параметрами (например, длина запрашиваемых данных), но не данные. В ответ сервер может передать клиенту данные произвольнойдлины. Обмен данными однонаправленный, в направлении от сервера к клиенту.
2. Команды группы write()
могут передать от клиента к серверу данные произвольнойдлины, но в ответ сервер может возвратить только код результата - число байт, фактически успешно полученных в результате операции. Обмен данными однонаправленный, в направлении от клиенту к серверу.
3. Команда devctl()
, использующаяся обычно для организации канала управления (но это не обязательно), в зависимости от кода команды может передавать данные либо к серверу (подобно write()
), либо от сервера (подобно read()
), либо в обоих направлениях за один обмен. Таким образом, этой командой может быть организован двунаправленныйобмен. Вообще говоря, принято считать, что по devctl()
передаются данные фиксированнойдлины: длина передаваемого блока данных определяется непосредственно кодом команды. Но это не является серьезным ограничением: мы можем динамически формировать код команды перед обменом исходя из объема данных, подлежащих передаче (как это будет показано в примере следующего раздела). Такой трюк позволяет организовать обмен данными произвольнойдлины. Ограничение здесь состоит в другом: объемы данных, передаваемые по devctl()
в обоих направлениях, должны быть равны! А это, согласитесь, не совсем то, что мы видели при простом обмене сообщениями.
Читать дальше
Конец ознакомительного отрывка
Купить книгу