Несколько замечаний о дескрипторах узлов
Несколько замечаний о дескрипторах узлов
Еще одна любопытная вещь, которой мы еще не касались в обсуждениях обмена сообщениями, — это дескрипторы узлов, для краткости обозначаемые «ND» (сокр. от Node Descriptor — прим. ред.).
Вспомните: в наших примерах мы использовали символьные имена узлов, например, /net/wintermute. В QNX4 (предыдущая версия QNX до появления QNX/Neutrino) вся работа в сети была основана на концепции идентификатора узла, небольшого целого числа, уникально определяющего узел сети. Таким образом, в терминах QNX4 мы говорили бы что-то вроде «узел 61», или «узел 1», и это отражалось бы и на вызовах функций тоже.
При работе в QNX/Neutrino все узлы внутренне представляются 32-разрядными числами, но эти числа не являются уникальными в сети! Я имею в виду, что узел wintermute может думать об узле spud как об узле с дескриптором 7, в то время как сам узел spud может думать, что дескриптор 7 соответствует узлу magenta. Поясню подробнее, чтобы дать полную картину происходящего. В приведенной ниже таблице сведены примерные дескрипторы узлов, которые могли бы использоваться для описания трех узлов: wintermute, spud и foobar (не путать с аббревиатурой FUBAR — прим. ред. :-):
Обратите внимание, что каждый узел считает свой собственный дескриптор нулевым. Также отметьте, что для узла spud оба узла wintermute и foobar имеют дескриптор 7. Однако, для узла foobar узел wintermute имеет дескриптор 4, а узел spud — 6. Как я и упоминал раньше, эти номера не уникальны в сети, но они уникальны на каждом узле. Вы можете относиться к ним, как к файловым дескрипторам — два процесса, когда обращаются к одному и тому же файлу, могут иметь для него как одинаковый дескриптор, так и нет — все зависит от того, кто, когда и который файл открывает.
К счастью, вам не надо беспокоиться о дескрипторах узлов по ряду причин:
• Большинство осуществляемых вами операций обмена сообщениями «с внешним миром» будут реализовываться с помощью вызовов функций высокого уровня (таких как функция open(), приведенная в примере выше).
• Дескрипторы узлов не кэшируются — предполагается, что получив дескриптор, вы используете немедленно и забудете про него.
• Существует ряд библиотечных функций, предназначенных для преобразования имени пути (например, /net/magenta) в дескриптор узла.
Чтобы работать с дескрипторами узлов, вам понадобится подключить файл <sys/netmgr.h>, потому что он содержит прототипы семейства функций netmgr_*().
Для преобразования строки в дескриптор узла используется функция netmgr_strtond(). После получения дескриптора узла его следует сразу же применить в вызове функции ConnectAttach(). Не пытайтесь сохранять его какой-либо структуре данных! Веским основанием для этого является то, что администратор сети может решить повторно использовать дескриптор после отключения всех соединений с узлом.
Так что если вы получили дескриптор «7» для узла /net/magenta, подсоединились к нему, передали сообщение и затем отсоединились, то существует возможность того, что администратор сети заново назначит дескриптор «7» другому узлу.
Поскольку дескрипторы узлов в сети не уникальны, возникает вопрос: «А как передавать эти штуки по сети?» Очевидно, взгляды узла magenta и узла wintermute на дескриптор «7» будут радикально отличаться. Существуют два способа решения этой проблемы:
• Не передавать по сети дескрипторы узлов и пользоваться символьными именами (например, /net/wintermute).
• Применять функцию netmgr_remote_nd().
Первый метод хорош как универсальное решение. Второй метод достаточно удобен на практике.
int netmgr_remote_nd(int remote_nd, int local_nd);
Эта функция принимает два параметра, где remote_nd — дескриптор узла целевой машины, a local_nd — дескриптор узла, который нужно преобразовать из точки зрения локальной машины в точку зрения целевой. Результатом является дескриптор узла, корректный с точки зрения заданной удаленной машины.
Например, пусть wintermute — имя нашей локальной машины. У нас есть дескриптор узла «7», который является корректным на нашей локальной машине и указывает на узел magenta. Мы хотели бы выяснить, какой дескриптор узла использует узел magenta для связи с нашим узлом:
int remote_nd;
int magenta_nd;
magenta_nd = netmgr_strtond("/net/magenta", NULL);
printf("ND узла magenta — %d ", magenta_nd);
remote_nd = netmgr_remote_nd(magenta_nd, ND_LOCAL_NODE);
printf("С точки зрения узла magenta, наш ND — %d ",
remote_nd);
Это программа могла бы вывести что-то вроде следующего:
ND узла magenta - 7
С точки зрения узла magenta, наш ND — 4
Это говорит о том, что на узле magenta нашему узлу соответствует дескриптор «4». (Обратите внимание на использование специальной константы ND_LOCAL_NODE, которая в действительности равна нулю, для указания на «локальный узел»).
Теперь вернемся к тому, о чем мы говорили в разделе «Кто послал сообщение?»). Параметр struct _msg_info содержит, среди всего прочего, два дескриптора узлов:
struct _msg_info {
int nd;
int srcnd;
...
};
Мы определили в описании для этих двух полей, что:
• nd — дескриптор принимающего узла с точки зрения передающего;
• srcnd — дескриптор передающего узла с точки зрения принимающего.
Так, для приведенного выше примера, где узел wintermute — локальный, а узел magenta — удаленный, когда узел magenta посылает нам (узлу wintermute) сообщение, эти поля заполняются следующим образом:
• nd равен 7;
• srcnd равен 4.