伺服器主機系統是執行分散式應用程式伺服器程式的計算機。 網路上可能有一或多個伺服器主機系統。 用戶端程式如何尋找要連線的伺服器,取決於您的程式需求。
尋找伺服器主機系統的方法有兩種:
- 使用儲存在用戶端原始碼、環境變數或應用程式特定組態檔中字串中的資訊。 用戶端應用程式可以使用字串中的數據來撰寫用戶端與伺服器之間的系結。
- 查詢伺服器程式位置的名稱服務資料庫。
本節提供下列主題中這兩種技術的相關信息:
使用字串系結
應用程式可以從儲存在字串中的資訊建立系結。 用戶端應用程式會將此資訊撰寫為字串,然後呼叫 rpcBindingFromStringBinding函式。 用戶端必須提供下列資訊來識別伺服器:
- 介面名稱、物件的全域唯一標識元(GUID)或物件的 UUID。 如需詳細資訊,請參閱 產生介面 UUID 和 字串 UUID。
- 要透過通訊的傳輸類型,例如命名管道或 TCP/IP。 如需詳細資訊,請參閱 基本 RPC 系結術語 和 選取通訊協定順序。
- 網路位址或伺服器主計算機的名稱。
- 伺服器主電腦上的伺服器程式端點。 如需詳細資訊,請參閱 尋找端點和 指定端點。
(物件 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:\\\\servername[\\pipe\\pipename]
客戶端接著會呼叫 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 名稱服務資料庫。