Поиск систем узла сервера
Серверная система — это компьютер, на котором выполняется серверная программа распределенного приложения. В сети может быть одна или несколько систем узла сервера. То, как клиентская программа находит сервер для подключения, зависит от потребностей программы.
Существует два метода поиска систем узла сервера:
- Использование сведений, хранящихся в строках в исходном коде клиента, переменных среды или файлах конфигурации конкретного приложения. Клиентское приложение может использовать данные в строке для создания привязки между клиентом и сервером.
- Запрос к базе данных службы имен для определения расположения серверной программы.
В этом разделе представлены сведения об обоих этих методах в следующих разделах:
Использование строковых привязок
Приложения могут создавать привязки на основе сведений, хранящихся в строках. Клиентское приложение создает эти сведения в виде строки, а затем вызывает функцию RpcBindingFromStringBinding . Клиент должен предоставить следующие сведения для идентификации сервера:
- Имя интерфейса, глобальный уникальный идентификатор (GUID) объекта или UUID объекта. Дополнительные сведения см. в разделах Создание идентификаторов UUID интерфейса и Строковый UUID.
- Тип транспорта для обмена данными, например именованные каналы или TCP/IP. Дополнительные сведения см. в разделах Основные термины привязки RPC и Выбор последовательности протокола.
- Сетевой адрес или имя главного компьютера сервера.
- Конечная точка серверной программы на хост-компьютере сервера. Дополнительные сведения см. в разделах Поиск конечных точек и Указание конечных точек.
(UUID объекта и сведения о конечной точке являются необязательными.)
В следующих примерах параметр pszNetworkAddress и другие параметры включают внедренные обратные косые черты. Обратная косая черта является escape-символом на языке программирования C. Для представления каждого отдельного символа обратной косой черты требуется два символа обратной косой черты. Структура привязки строк должна содержать четыре символа обратной косой черты для представления двух символов обратной косой черты, предшествующих имени сервера.
В следующем примере показано, что имени сервера должны предшествовать восемь обратных косых черт, чтобы четыре символа обратной косой черты отображались в структуре данных привязки строк после обработки строки функцией sprintf_s .
/* client application */
char * pszUuid = "6B29FC40-CA47-1067-B31D-00DD010662DA";
char * pszProtocol = "ncacn_np";
char * pszNetworkAddress = "\\\\\\\\servername";
char * pszEndpoint = "\\\\pipe\\\\pipename";
char * pszString;
int len = 0;
len = sprintf_s(pszString, strlen(pszUuid), "%s", pszUuid);
len += sprintf_s(pszString + len, strlen(pszProtocolSequence) + 2, "@%s:",
pszProtocolSequence);
if (pszNetworkAddress != NULL)
len += sprintf_s(pszString + len, strlen(pszNetworkAddress), "%s",
pszNetworkAddress);
len += sprintf_s(pszString + len, strlen(pszEndpoint) + 2, "[%s]", pszEndpoint);
В следующем примере строковая привязка выглядит следующим образом:
6B29FC40-CA47-1067-B31D-00DD010662DA@ncacn_np:\\\\имя_сервера[\\pipe\\имя_канала]
Затем клиент вызывает RpcBindingFromStringBinding, чтобы получить дескриптор привязки:
RPC_BINDING_HANDLE hBinding;
status = RpcBindingFromStringBinding(pszString, &hBinding);
//...
Удобная функция RpcStringBindingCompose собирает UUID объекта, последовательность протокола, сетевой адрес и конечную точку в правильном синтаксисе для вызова RpcBindingFromStringBinding. Вам не нужно беспокоиться о том, чтобы поместить амперсанд, двоеточие и различные компоненты для каждой последовательности протокола в нужное место; вы просто указываете строки в качестве параметров для функции. Библиотека времени выполнения даже выделяет память, необходимую для привязки строки.
char * pszNetworkAddress = "\\\\server";
char * pszEndpoint = "\\pipe\\pipename";
status = RpcStringBindingCompose(
pszUuid,
pszProtocolSequence,
pszNetworkAddress,
pszEndpoint,
pszOptions,
&pszString);
//...
status = RpcBindingFromStringBinding(
pszString,
&hBinding);
//...
Другая удобная функция , RpcBindingToStringBinding, принимает дескриптор привязки в качестве входных данных и создает соответствующую строковую привязку.
Импорт из баз данных службы имен
В базах данных службы имен хранятся, помимо прочего, дескрипторы привязки и идентификаторы UUID. Клиентское приложение может выполнять поиск по одному из них или обоим, когда ему требуется выполнить привязку к серверу. Сведения о том, что хранит служба имен, и формат хранилища см. в разделе База данных службы имен RPC.
Библиотека RPC предоставляет два набора функций, которые клиентская программа может использовать для поиска в базе данных службы имен. Имена одного набора начинаются с RpcNsBindingImport. Имена другого набора начинаются с RpcNsBindingLookup. Разница между двумя группами функций заключается в том, что функции RpcNsBindingImport возвращают один дескриптор привязки для каждого вызова, а функции RpcNsBindingLookup возвращают группы дескрипторов для каждого вызова.
Чтобы начать поиск с помощью функций RpcNsBindingImport, сначала вызовите RpcNsBindingImportBegin, как показано в следующем фрагменте кода.
RPC_STATUS status;
RPC_NS_HANDLE hNameServiceHandle;
status = RpcNsBindingImportBegin(
RPC_C_NS_SYNTAX_DEFAULT,
NULL,
MyInterface_v1_0_c_ifspec,
NULL,
&hNameServiceHandle);
Когда функции RPC выполняют поиск в базе данных службы имен, им нужно место, чтобы начать поиск. В терминологии RPC это называется именем записи. Клиентская программа передает имя записи в качестве второго параметра в RpcNsBindingImportBegin. Этот параметр может иметь значение NULL , если требуется выполнить поиск по всей базе данных службы имен. Кроме того, можно выполнить поиск в записи сервера, передав имя записи сервера, или выполнить поиск в записи группы, передав имя записи группы. Передача имени записи ограничивает поиск только содержимым этой записи.
В предыдущем примере значение RPC_C_NS_SYNTAX_DEFAULT передается в качестве первого параметра в RpcNsBindingImportBegin. При этом выбирается синтаксис имени записи по умолчанию. В настоящее время это единственный поддерживаемый синтаксис имени входа.
Клиентское приложение может искать имя интерфейса, UUID или и то, и другое в базе данных службы имен. Если вы хотите, чтобы он искал интерфейс по имени, передайте глобальную переменную интерфейса, созданную компилятором MIDL из IDL-файла, в качестве третьего параметра в RpcNsBindingImportBegin. Вы найдете его объявление в файле заголовка, созданном компилятором MIDL при создании клиентской заглушки. Если вы хотите, чтобы клиентская программа выполняла поиск только по UUID, присвойте третьему параметру значение NULL.
При поиске UUID в базе данных службы имен задайте для четвертого параметра RpcNsBindingImportBegin значение UUID, который требуется найти. Если вы не ищете UUID, задайте для этого параметра значение NULL.
Функция RpcNsBindingImportBegin передает адрес дескриптора контекста поиска имени через свой пятый параметр. Этот параметр передается другим функциям RpcNsBindingImport.
В частности, следующая функция, вызываемая клиентским приложением, — RpcNsBindingImportNext. Клиентские программы используют эту функцию для получения совместимых дескрипторов привязки из базы данных службы имен. В следующем фрагменте кода показано, как можно вызывать эту функцию:
RPC_STATUS status;
RPC_BINDING_HANDLE hBindingHandle;
// The variable hNameServiceHandle is a valid name service search
// context handle obtained from the RpcNsBindingBegin function.
status = RpcNsBindingImportNext(hNameServiceHandle, &hBindingHandle);
После вызова функции RpcNsBindingImportNext для получения дескриптора привязки клиентское приложение сможет определить, приемлем ли полученный дескриптор. В противном случае клиентская программа может выполнить цикл и снова вызвать RpcNsBindingImportNext , чтобы проверить, содержит ли служба имен более подходящий дескриптор. Для каждого вызова RpcNsBindingImportNext должен быть соответствующий вызов RpcNsBindingFree. После завершения поиска вызовите функцию RpcNsBindingImportDone , чтобы освободить контекст поиска.
После того как клиентское приложение имеет допустимый дескриптор привязки, оно должно проверка, чтобы убедиться, что серверное приложение запущено. Существует два метода, которые клиент может использовать для выполнения этой проверки. Первый — вызвать функцию в клиентском интерфейсе. Если серверная программа запущена, вызов завершится. В противном случае вызов завершится ошибкой. Лучший способ убедиться, что сервер работает, — вызвать RpcEpResolveBinding, а затем вызвать RpcMgmtIsServerListening. Дополнительные сведения о базе данных службы имен см. в разделе База данных службы имен RPC.