могут передать от клиента к серверу данные произвольнойдлины, но в ответ сервер может возвратить только код результата - число байт, фактически успешно полученных в результате операции. Обмен данными однонаправленный, в направлении от клиенту к серверу.
3. Команда
devctl
, использующаяся обычно для организации канала управления (но это не обязательно), в зависимости от кода команды может передавать данные либо к серверу (подобно
write
), либо от сервера (подобно
read
), либо в обоих направлениях
за один обмен. Таким образом, этой командой может быть организован двунаправленныйобмен. Вообще говоря, принято считать, что по
devctl
передаются данные фиксированнойдлины: длина передаваемого блока данных определяется непосредственно кодом команды. Но это не является серьезным ограничением: мы можем динамически формировать код команды перед обменом исходя из объема данных, подлежащих передаче (как это будет показано в примере следующего раздела). Такой трюк позволяет организовать обмен данными произвольнойдлины. Ограничение здесь состоит в другом: объемы данных, передаваемые по
devctl
в обоих направлениях, должны быть равны! А это, согласитесь, не совсем то, что мы видели при простом обмене сообщениями.
4. Наконец, последним вариантом обмена с менеджером ресурса является обмен «сырыми», неформатированными сообщениями. Но это уже вариация простого обмена сообщениями, а как ее реализовать в коде, показано в приложении В. Зайцева.
С другой стороны, такая повышенная гибкость простого обмена сообщениями в отношении размеров передаваемых данных — предмет потенциальных ошибок, в то время как регламентируемое POSIX поведение обменных функций несет в себе дополнительный контроль корректности.
Эффективность реализации
Если техника менеджеров ресурсов — это только надстройка над базовым механизмом обмена сообщениями, то возникает совершенно естественный вопрос: какова же плата за использование этого производительного и «комфортного» механизма?
Для анализа «скоростных» характеристик альтернативных механизмов обмена сообщениями создадим группу приложений (клиентские и сервер, файлы cli.cc, clr.ccи srv.cc), а чтобы отдельно не выписывать определения, используемые приложениями, вынесем их в отдельный файл определений ( файл common.h).
Общие определения проекта
const char VERSION[] = "vers. 1.03";
// имя, под которым будет регистрироваться в пространстве
// структура ответов менеджера ресурса по запросу read
struct result {
pid_t pid;
int chid;
uint64_t cps;
result(void) {
pid = getpid;
//
если уж возвращать, то и служебную информацию ;)
cps = SYSPAGE_ENTRY(qtime)->cycles_per_sec;
}
}
// завершение с извещением кода причины
inline void exit(const char *msg) {
cout << '\r';
perror(msg);
exit(EXIT_FAILURE);
}
В этой части каких-либо комментариев заслуживает разве что структура
result
. Наш сервер устроен «наоборот»: информационный обмен данными он осуществляет по запросу
devctl
, запрос
read
нам «не нужен», и мы используем его только для возврата информации (PID + CHID) об автономном канале обмена сообщениями. Заодно мы передаем в поле cps этой структуры значение тактовой частоты процессора сервера, что позволяет знать, «с кем мы имеем дело» при экспериментах в сети.
Теперь мы вполне готовы написать код сервера. Этот сервер ( файл srv.cc), в отличие от традиционных, имеет два независимых канала подключения: как менеджер ресурсов и как сервер простого обмена сообщениями. Как менеджер он по запросу
read
возвращает адресные компоненты (PID, CHID) для обмена сообщениями (ND клиент должен восстановить самостоятельно). По запросу
devctl
, а также по запросу по автономному каналу обмена сообщениями сервер просто ретранслирует обратно полученный от клиента блок данных (в каком-то смысле по обоим каналам обмена наш сервер является «зеркалом», отражающим данные).