Ricerca di sistemi host server

Un sistema host server è il computer che esegue il programma server dell'applicazione distribuita. In una rete possono essere presenti uno o più sistemi host server. Il modo in cui il programma client trova un server a cui connettersi dipende dalle esigenze del programma.

Esistono due metodi per trovare i sistemi host del server:

  • Uso delle informazioni archiviate in stringhe nel codice sorgente del client, nelle variabili di ambiente o nei file di configurazione specifici dell'applicazione. L'applicazione client può usare i dati nella stringa per comporre un'associazione tra il client e il server.
  • Esecuzione di query su un database del servizio dei nomi per il percorso di un programma server.

Questa sezione presenta informazioni su entrambe queste tecniche negli argomenti seguenti:

Uso delle associazioni di stringhe

Le applicazioni possono creare associazioni da informazioni archiviate in stringhe. L'applicazione client compone queste informazioni come stringa, quindi chiama la funzione RpcBindingFromStringBinding. Il client deve fornire le informazioni seguenti per identificare il server:

L'UUID dell'oggetto e le informazioni sull'endpoint sono facoltative.

Negli esempi seguenti il parametro pszNetworkAddress e altri parametri includono barre rovesciate incorporate. La barra rovesciata è un carattere di escape nel linguaggio di programmazione C. Sono necessarie due barre rovesciata per rappresentare ogni singolo carattere barra rovesciata letterale. La struttura di associazione di stringhe deve contenere quattro caratteri barra rovesciata per rappresentare i due caratteri barra rovesciata letterale che precedono il nome del server.

L'esempio seguente mostra che il nome del server deve essere preceduto da otto barre rovesciate in modo che quattro caratteri barra rovesciata letterale vengano visualizzati nella struttura dei dati di associazione di stringhe dopo che la funzione sprintf_s elabora la stringa.

/* 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);

Nell'esempio seguente l'associazione di stringhe viene visualizzata come:

6B29FC40-CA47-1067-B31D-00DD010662DA@ncacn_np:\\\\nomeserver[\\pipe\\pipename]

Il client chiama quindi RpcBindingFromStringBinding per ottenere l'handle di associazione:

RPC_BINDING_HANDLE hBinding;
 
status = RpcBindingFromStringBinding(pszString, &hBinding);
//...

Una funzione utile , RpcStringBindingCompose assembla l'UUID dell'oggetto, la sequenza di protocollo, l'indirizzo di rete e l'endpoint nella sintassi corretta per la chiamata a RpcBindingFromStringBinding. Non è necessario preoccuparsi di inserire l'e commerciale, i due punti e i vari componenti per ogni sequenza di protocollo nel posto giusto; è sufficiente fornire le stringhe come parametri alla funzione. La libreria di runtime alloca anche la memoria necessaria per l'associazione di stringhe.

char * pszNetworkAddress = "\\\\server";
char * pszEndpoint = "\\pipe\\pipename";
status = RpcStringBindingCompose(
            pszUuid,
            pszProtocolSequence,
            pszNetworkAddress,
            pszEndpoint,
            pszOptions,
            &pszString);
//...
status = RpcBindingFromStringBinding(
            pszString,
            &hBinding);
//...

Un'altra funzione utile , RpcBindingToStringBinding, accetta un handle di associazione come input e produce l'associazione di stringa corrispondente.

Importazione da database del servizio dei nomi

I database del servizio dei nomi archiviano, tra le altre cose, handle di associazione e UUID. L'applicazione client può cercare uno o entrambi questi elementi quando deve eseguire l'associazione al server. Per informazioni sulle informazioni archiviate da un servizio dei nomi e sul formato di archiviazione, vedere Database del servizio dei nomi RPC.

La libreria RPC fornisce due set di funzioni che il programma client può usare per eseguire ricerche nel database del servizio dei nomi. I nomi di un set iniziano con RpcNsBindingImport. I nomi dell'altro set iniziano con RpcNsBindingLookup. La differenza tra i due gruppi di funzioni è che le funzioni RpcNsBindingImport restituiscono un singolo handle di associazione per chiamata e le funzioni RpcNsBindingLookup restituiscono gruppi di handle per chiamata.

Per iniziare una ricerca con le funzioni RpcNsBindingImport, chiamare prima RpcNsBindingImportBegin, come illustrato nel frammento di codice seguente.

RPC_STATUS status;
RPC_NS_HANDLE hNameServiceHandle;
 
status = RpcNsBindingImportBegin(
    RPC_C_NS_SYNTAX_DEFAULT,
    NULL,
    MyInterface_v1_0_c_ifspec,
    NULL,
    &hNameServiceHandle);

Quando le funzioni RPC esedono la ricerca nel database del servizio dei nomi, è necessario un punto in cui iniziare la ricerca. Nella terminologia RPC, questo nome viene chiamato nome della voce. Il programma client passa il nome della voce come secondo parametro a RpcNsBindingImportBegin. Questo parametro può essere NULL se si desidera eseguire una ricerca nell'intero database del servizio dei nomi. In alternativa, è possibile cercare la voce del server passando un nome di voce del server o cercando la voce di gruppo passando un nome di voce di gruppo. Il passaggio di un nome di voce limita la ricerca al contenuto di tale voce.

Nell'esempio precedente il valore RPC_C_NS_SYNTAX_DEFAULT viene passato come primo parametro a RpcNsBindingImportBegin. In questo modo viene selezionata la sintassi predefinita del nome della voce. Attualmente, si tratta dell'unica sintassi di entry-name supportata.

L'applicazione client può cercare nel database del servizio dei nomi un nome di interfaccia, un UUID o entrambi. Se si vuole eseguire la ricerca di un'interfaccia in base al nome, passare la variabile di interfaccia globale generata dal compilatore MIDL dal file IDL come terzo parametro a RpcNsBindingImportBegin. La dichiarazione è disponibile nel file di intestazione generato dal compilatore MIDL quando ha generato lo stub del client. Se si vuole che il programma client esequisi solo in base all'UUID, impostare il terzo parametro su NULL.

Quando si cerca un UUID nel database del servizio dei nomi, impostare il quarto parametro di RpcNsBindingImportBegin sull'UUID da cercare. Se non si sta cercando un UUID, impostare questo parametro su NULL.

La funzione RpcNsBindingImportBegin passa l'indirizzo di un contesto di ricerca del servizio dei nomi gestito tramite il quinto parametro. Questo parametro viene passato ad altre funzioni RpcNsBindingImport.

In particolare, la funzione successiva che l'applicazione client chiamerebbe è RpcNsBindingImportNext. I programmi client usano questa funzione per recuperare handle di associazione compatibili dal database del servizio dei nomi. Il frammento di codice seguente illustra come questa funzione può essere chiamata:

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);

Dopo aver chiamato la funzione RpcNsBindingImportNext per ottenere un handle di associazione, l'applicazione client può determinare se l'handle ricevuto è accettabile. In caso contrario, il programma client può eseguire un ciclo e chiamare nuovamente RpcNsBindingImportNext per verificare se il servizio dei nomi contiene un handle più appropriato. Per ogni chiamata a RpcNsBindingImportNext, deve essere presente una chiamata corrispondente a RpcNsBindingFree. Al termine della ricerca, chiamare la funzione RpcNsBindingImportDone per liberare il contesto di ricerca.

Dopo che l'applicazione client ha un handle di associazione accettabile, deve verificare che l'applicazione server sia in esecuzione. Esistono due metodi che il client può usare per eseguire questa verifica. Il primo consiste nel chiamare una funzione nell'interfaccia client. Se il programma server è in esecuzione, la chiamata verrà completata. In caso contrario, la chiamata avrà esito negativo. Un modo migliore per verificare che il server sia in esecuzione consiste nel richiamare RpcEpResolveBinding, seguita da una chiamata a RpcMgmtIsServerListening. Per altre informazioni sul database del servizio dei nomi, vedere Database del servizio nome RPC.