サーバー ホスト システムの検索
サーバー ホスト システムは、分散アプリケーションのサーバー プログラムを実行するコンピューターです。 ネットワーク上に 1 つまたは複数のサーバー ホスト システムが存在する可能性があります。 クライアント プログラムが接続先のサーバーを見つける方法は、プログラムのニーズによって異なります。
サーバー ホスト システムを検索するには、次の 2 つの方法があります。
- クライアントのソース コード、環境変数、またはアプリケーション固有の構成ファイル内の文字列に格納されている情報を使用する。 クライアント アプリケーションは、文字列内のデータを使用して、クライアントとサーバーの間のバインディングを構成できます。
- サーバー プログラムの場所をネーム サービス データベースに照会する。
このセクションでは、次のトピックでこれらの手法の両方について説明します。
文字列バインディングの使用
アプリケーションでは、文字列に格納されている情報からバインドを作成できます。 クライアント アプリケーションは、この情報を文字列として作成し、 RpcBindingFromStringBinding 関数を 呼び出します。 クライアントは、サーバーを識別するために次の情報を提供する必要があります。
- インターフェイス名、オブジェクトのグローバル一意識別子 (GUID)、またはオブジェクトの UUID。 詳細については、「 インターフェイス UUID の生成 」と 「文字列 UUID」を参照してください。
- 名前付きパイプや TCP/IP など、通信するトランスポートの種類。 詳細については、「 基本的な RPC バインディングの用語 」および 「プロトコル シーケンスの選択」を参照してください。
- ネットワーク アドレスまたはサーバー ホスト コンピューターの名前。
- サーバー ホスト コンピューター上のサーバー プログラムのエンドポイント。 詳細については、「 エンドポイントの検索」および「 エンドポイントの指定」を参照してください。
(オブジェクト UUID とエンドポイント情報は省略可能です)。
次の例では、 pszNetworkAddress パラメーターとその他のパラメーターに埋め込み円記号が含まれています。 円記号は、C プログラミング言語のエスケープ文字です。 各リテラル円記号文字を表すには、2 つの円記号が必要です。 サーバー名の前にある 2 つのリテラル円記号文字を表すには、文字列バインディング構造体に 4 つの円記号文字を含める必要があります。
次の例は、サーバー名の前に 8 個の円記号を付けて、sprintf_s関数が文字列を処理した後に 4 つのリテラル 円記号文字 が 文字列バインディング データ構造に表示されるようにする必要があることを示しています。
/* 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:\\\\servername[\\pipe\\pipename]
次に、クライアントは RpcBindingFromStringBinding を 呼び出してバインド ハンドルを取得します。
RPC_BINDING_HANDLE hBinding;
status = RpcBindingFromStringBinding(pszString, &hBinding);
//...
便利な関数 RpcStringBindingCompose は 、 RpcBindingFromStringBinding の呼び出しに適した構文で、オブジェクト UUID、プロトコル シーケンス、ネットワーク アドレス、およびエンドポイントをアセンブルします。 アンパサンド、コロン、および各プロトコル シーケンスのさまざまなコンポーネントを適切な場所に配置することを心配する必要はありません。文字列をパラメーターとして関数に指定するだけです。 ランタイム ライブラリでは、文字列バインディングに必要なメモリも割り当てられます。
char * pszNetworkAddress = "\\\\server";
char * pszEndpoint = "\\pipe\\pipename";
status = RpcStringBindingCompose(
pszUuid,
pszProtocolSequence,
pszNetworkAddress,
pszEndpoint,
pszOptions,
&pszString);
//...
status = RpcBindingFromStringBinding(
pszString,
&hBinding);
//...
もう 1 つの便利な関数 RpcBindingToStringBinding は、入力としてバインド ハンドルを受け取り、対応する文字列バインドを生成します。
Name Service データベースからのインポート
名前サービス データベースには、バインディング ハンドルと UUID などが格納されます。 クライアント アプリケーションは、サーバーにバインドする必要がある場合に、これらのいずれかまたは両方を検索できます。 ネーム サービスが格納する情報とストレージ形式の詳細については、「 RPC Name Service Database」を参照してください。
RPC ライブラリには、クライアント プログラムがネーム サービス データベースの検索に使用できる 2 つの関数セットが用意されています。 1 つのセットの名前は、RpcNsBindingImport で始まります。 他のセットの名前は、RpcNsBindingLookup で始まります。 関数の 2 つのグループの違いは、RpcNsBindingImport 関数が呼び出しごとに 1 つのバインド ハンドルを返し、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 の用語では、これはエントリ名と呼ばれます。 クライアント プログラムは、エントリ名を 2 番目のパラメーターとして RpcNsBindingImportBegin に渡します。 ネーム サービス データベース全体を検索する場合は、このパラメーターを NULL にすることができます 。 または、サーバーエントリ名を渡してサーバーエントリを検索するか、グループエントリ名を渡してグループエントリを検索することもできます。 エントリ名を渡すと、検索はそのエントリの内容に制限されます。
前の例では、RPC_C_NS_SYNTAX_DEFAULT値が最初のパラメーターとして RpcNsBindingImportBegin に渡されます。 これにより、既定のエントリ名構文が選択されます。 現在、これはサポートされている唯一のエントリ名構文です。
クライアント アプリケーションは、名前サービス データベースでインターフェイス名、UUID、またはその両方を検索できます。 インターフェイスを名前で検索する場合は、IDL ファイルから生成されるグローバル インターフェイス変数を 3 番目のパラメーターとして RpcNsBindingImportBegin に渡します。 その宣言は、MIDL コンパイラがクライアント スタブの生成時に生成したヘッダー ファイルにあります。 クライアント プログラムで UUID のみで検索する場合は、3 番目のパラメーターを NULL に設定 します。
ネーム サービス データベースで UUID を検索する場合は、 RpcNsBindingImportBegin の 4 番目のパラメーターを、検索する UUID に設定します。 UUID を検索しない場合は、このパラメーターを NULL に設定 します。
RpcNsBindingImportBegin 関数は、5 番目のパラメーターを介して name service-search コンテキスト ハンドルのアドレスを渡します。 このパラメーターは、他の 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 関数を 呼び出して、参照コンテキストを解放します。
クライアント アプリケーションに受け入れ可能なバインド ハンドルが設定されたら、サーバー アプリケーションが実行されていることを確認するためにチェックする必要があります。 この検証を実行するためにクライアントで使用できる方法は 2 つあります。 1 つ目は、クライアント インターフェイスで 関数を呼び出す方法です。 サーバー プログラムが実行されている場合、呼び出しは完了します。 そうでない場合、呼び出しは失敗します。 サーバーが実行されていることを確認するより良い方法は、 RpcEpResolveBinding を呼び出し、その後に RpcMgmtIsServerListening を呼び出す方法です。 ネーム サービス データベースの詳細については、「 RPC Name Service Database」を参照してください。