尋找伺服器主機系統
伺服器主機系統是執行分散式應用程式伺服器程式的電腦。 網路上可能有一或多個伺服器主機系統。 用戶端程式如何尋找要連線的伺服器,取決於您的程式需求。
尋找伺服器主機系統的方法有兩種:
- 使用儲存在用戶端原始程式碼、環境變數或應用程式特定組態檔中字串中的資訊。 用戶端應用程式可以使用字串中的資料來撰寫用戶端與伺服器之間的系結。
- 查詢名稱服務資料庫以取得伺服器程式的位置。
本節提供下列主題中這兩種技術的相關資訊:
使用字串系結
應用程式可以從儲存在字串中的資訊建立系結。 用戶端應用程式會將此資訊撰寫為字串,然後呼叫 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\\pipe\\pipename]
用戶端接著會呼叫 RpcBindingFromStringBinding 以取得系結控制碼:
RPC_BINDING_HANDLE hBinding;
status = RpcBindingFromStringBinding(pszString, &hBinding);
//...
方便的函式 RpcStringBindingCompose 會以 RpcBindingFromStringBinding呼叫的正確語法組合物件 UUID、通訊協定序列、網路位址和端點。 您不需要擔心將每個通訊協定序列的 ampersand、冒號和各種元件放在正確的位置;您只要提供字串做為函式的參數即可。 執行時間程式庫甚至會配置字串系結所需的記憶體。
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 名稱服務資料庫。