Прочитать на английском

Поделиться через


Поиск серверных хост-систем

Серверная система — это компьютер, который выполняет серверную программу распределенного приложения. В сети может быть одна или несколько систем узлов сервера. Как клиентская программа находит сервер для подключения, зависит от потребностей вашей программы.

Существует два метода поиска систем узлов сервера:

  • Использование сведений, хранящихся в строках в исходном коде клиента, переменных среды или файлах конфигурации для конкретного приложения. Клиентское приложение может использовать данные в строке для создания привязки между клиентом и сервером.
  • Запрос к базе данных службы имен для нахождения серверной программы.

В этом разделе представлены сведения о обоих этих методах в следующих разделах:

Использование строковых привязок

Приложения могут создавать привязки из информации, хранящейся в строках. Клиентское приложение формирует эту информацию в виде строки, а затем вызывает функцию RpcBindingFromStringBinding. Клиент должен предоставить следующие сведения для идентификации сервера:

(Сведения об объекте UUID и конечной точке являются необязательными.)

В следующих примерах параметр pszNetworkAddress и другие параметры включают встроенные обратные косые черты. Обратная косая черта — это символ экранирования в языке программирования 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.