if ((dpp = dispatch_create()) == NULL) {
perror("Ошибка dispatch_create\n");
exit(EXIT_FAILURE);
}
// Инициализировать структуры данных
memset(&resmgr_attr, 0, sizeof(resmgr_attr));
resmgr_attr.nparts_max = 1;
resmgr_attr.msg_max_size = 2048;
// Назначить вызовам обработчики по умолчанию
iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &connect_func,
_RESMGR_IO_NFUNCS, &io_func);
iofunc_attr_init(&attr, S_IFNAM | 0666, 0, 0);
// Зарегистрировать префикс в пространстве имен путей
if (resmgr_attach(dpp, &resmgr_attr,
"/dev/mynull", _FTYPE_ANY,
0, &connect_func, &io_func, &attr) == -1) {
perror("Ошибка resmgr_attach\n");
exit(EXIT_FAILURE);
}
ctp = resmgr_context_alloc(dpp);
// Ждать сообщений в вечном цикле
while (1) (
if ((ctp = resmgr_block(ctp)) == NULL) {
perror("Ошибка resmgr_block\n");
exit(EXIT_FAILURE);
}
resmgr_handler(ctp);
}
}
И все! Полнофункциональный администратор ресурса /dev/null
реализуется всего несколькими вызовами функций!
Если бы пришлось писать аналогичный по функциональности администратор (то есть с поддержкой функций
Реально все это за вас делает библиотека
Как вариант начального знакомства с библиотекой, давайте посмотрим, что делают вызовы, использованные в администраторе ресурсов /dev/null
:
Создает структуру диспетчеризации; она будет использоваться для блокирования по приему сообщения.
Инициализирует используемую устройством атрибутную запись. Мы обсудим атрибутные записи в подробностях несколько позже, а вкратце так: атрибутная запись содержит информацию об устройстве, и на каждое имя устройства имеется по одной атрибутной записи.
Инициализирует две структуры данных,
Создает канал, который администратор ресурса будет использовать для приема сообщений, и говорит администратору процессов, что мы намерены отвечать за «/dev/null
». Параметров тут много, но к этой головной боли мы вернемся несколько позже. Сейчас же важно отметить, что именно здесь связываются воедино дескриптор диспетчера (/dev/null
») и обработчики функций установления соединения (
Выделяет внутренний контекстный блок администратора ресурса. Мы рассмотрим этот блок в подробностях несколько позже, а вкратце — он содержит информацию, относящуюся к обрабатываемому сообщению.
Это блокирующий вызов администратора ресурса — функция, с помощью которой мы ожидаем сообщение от клиента.
После того как сообщение от клиента получено, для его обработки вызывается эта функция.
За кулисами библиотеки
Вы уже видели, что наша программа ответственна за предоставление основного рабочего цикла приема сообщений:
while (1) {
// Здесь ждем сообщения
if ((ctp = resmgr_block(ctp)) == NULL) {
perror("Unable to resmgr_block\n");
exit(EXIT_FAILURE);
}
// Обработать сообщение
resmgr_handler(ctp);
}
Это очень удобно, поскольку позволяет вам помещать точки останова на принимающей функции и перехватывать сообщения (например, с помощью отладчика) в процессе работы.