Partilhar via


Localizando sistemas de servidor

Um sistema host de servidor é o computador que executa o programa de servidor do aplicativo distribuído. Pode haver um ou vários sistemas host de servidor em uma rede. Como seu programa cliente encontra um servidor para se conectar depende das necessidades do seu programa.

Há dois métodos para localizar sistemas host de servidor:

  • Usando informações armazenadas em cadeias de caracteres no código-fonte do cliente, variáveis de ambiente ou arquivos de configuração específicos do aplicativo. Seu aplicativo cliente pode usar os dados na cadeia de caracteres para compor uma associação entre o cliente e o servidor.
  • Consulta a uma base de dados de serviço de nomes em busca da localização de um programa de servidor.

Esta seção apresenta informações sobre essas duas técnicas nos seguintes tópicos:

Usando ligações de cadeia de caracteres

Os aplicativos podem criar associações a partir de informações armazenadas em cadeias de caracteres. O seu aplicativo cliente compõe essas informações como uma cadeia de caracteres e, em seguida, invoca a função RpcBindingFromStringBinding. O cliente deve fornecer as seguintes informações para identificar o servidor:

(O UUID do objeto e as informações do ponto de extremidade são opcionais.)

Nos exemplos a seguir, o parâmetro pszNetworkAddress e outros parâmetros incluem barras invertidas incorporadas. A barra invertida é um caractere de escape na linguagem de programação C. Duas barras invertidas são necessárias para representar cada caractere de barra invertida literal. A estrutura de vinculação de cadeia de caracteres deve conter quatro caracteres de barra invertida para representar os dois caracteres de barra invertida literais que precedem o nome do servidor.

O exemplo a seguir mostra que o nome do servidor deve ser precedido por oito barras invertidas para que quatro caracteres de barra invertida literais apareçam na estrutura de dados de vinculação de cadeia de caracteres depois que a função sprintf_s processar a cadeia de caracteres.

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

No exemplo a seguir, a associação de cadeia de caracteres aparece como:

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

Em seguida, o cliente chama RpcBindingFromStringBinding para obter o identificador de ligação:

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

Uma função de conveniência, RpcStringBindingCompose, monta o UUID do objeto, a sequência de protocolo, o endereço de rede e o ponto de extremidade na sintaxe correta para a chamada de RpcBindingFromStringBinding. Você não precisa se preocupar em colocar o e comercial, o cólon e os vários componentes de cada sequência de protocolo no lugar certo; basta fornecer as strings como parâmetros para a função. A biblioteca de tempo de execução até aloca a memória necessária para a associação de cadeia de caracteres.

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

Outra função de conveniência, RpcBindingToStringBinding, toma como entrada um identificador de ligação e produz a ligação em formato de cadeia de caracteres correspondente.

Importando de Bases de Dados do Serviço de Nomes

Os bancos de dados do serviço de nomes armazenam, entre outras coisas, identificadores de vinculação e UUIDs. Seu aplicativo cliente pode procurar um ou ambos quando precisar se vincular ao servidor. Para obter uma discussão sobre as informações que um serviço de nome armazena e o formato de armazenamento, consulte The RPC Name Service Database.

A biblioteca RPC fornece dois conjuntos de funções que o programa cliente pode usar para pesquisar o banco de dados do serviço de nomes. Os nomes de um conjunto começam com RpcNsBindingImport. Os nomes do outro conjunto começam com RpcNsBindingLookup. A diferença entre os dois grupos de funções é que as funções RpcNsBindingImport retornam um único identificador de ligação por chamada e as funções RpcNsBindingLookup retornam grupos de identificadores por chamada.

Para iniciar uma pesquisa com as funções RpcNsBindingImport, primeiro chame RpcNsBindingImportBegin, conforme mostrado no fragmento de código a seguir.

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

Quando as funções RPC pesquisam o banco de dados do serviço de nomes, elas precisam de um local para iniciar a pesquisa. Na terminologia RPC, isso é chamado de nome da entrada. O programa cliente passa o nome da entrada como o segundo parâmetro para RpcNsBindingImportBegin. Esse parâmetro pode ser NULL se você quiser pesquisar todo o banco de dados do serviço de nomes. Em alternativa, pode pesquisar a entrada do servidor introduzindo um nome de entrada de servidor ou pesquisar a entrada do grupo introduzindo um nome de entrada de grupo. Passar um nome de entrada restringe a pesquisa ao conteúdo dessa entrada.

No exemplo anterior, o valor RPC_C_NS_SYNTAX_DEFAULT é passado como o primeiro parâmetro para RpcNsBindingImportBegin. Isso seleciona a sintaxe de nome de entrada padrão. Atualmente, esta é a única sintaxe de nome de entrada suportada.

Seu aplicativo cliente pode pesquisar no banco de dados do serviço de nomes um nome de interface, um UUID ou ambos. Se você quiser que ele procure uma interface por nome, passe a variável de interface global que o compilador MIDL gera do seu arquivo IDL como o terceiro parâmetro para RpcNsBindingImportBegin. Você encontrará sua declaração no arquivo de cabeçalho que o compilador MIDL gerou quando gerou o stub do cliente. Se você quiser que seu programa cliente pesquise apenas por UUID, defina o terceiro parâmetro como NULL.

Ao pesquisar um UUID no banco de dados do serviço de nomes, defina o quarto parâmetro de RpcNsBindingImportBegin para o UUID que você deseja pesquisar. Se você não estiver procurando por um UUID, defina esse parâmetro como NULL.

A funçãoRpcNsBindingImportBegin passa o endereço de um identificador de contexto de pesquisa de serviço de nome através de seu quinto parâmetro. Você passa esse parâmetro para outras funções RpcNsBindingImport.

Em particular, a próxima função que seu aplicativo cliente chamaria é RpcNsBindingImportNext. Os programas cliente usam essa função para recuperar identificadores de vinculação compatíveis do banco de dados do serviço de nomes. O fragmento de código a seguir demonstra como essa função pode ser chamada:

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

Depois de chamar a função RpcNsBindingImportNext para obter um identificador de ligação, seu aplicativo cliente pode determinar se o identificador recebido é aceitável. Se não, seu programa cliente pode executar um loop e chamar RpcNsBindingImportNext novamente para ver se o serviço de nome contém um identificador mais apropriado. Para cada chamada para RpcNsBindingImportNext, deve haver uma chamada correspondente para RpcNsBindingFree. Quando a pesquisa estiver concluída, chame a função RpcNsBindingImportDone para libertar o contexto de pesquisa.

Depois que seu aplicativo cliente tiver um identificador de vinculação aceitável, ele deve verificar se o aplicativo de servidor está em execução. Há dois métodos que seu cliente pode usar para executar essa verificação. A primeira é chamar uma função na interface do cliente. Se o programa do servidor estiver em execução, a chamada será concluída. Caso contrário, a chamada falhará. Uma maneira melhor de verificar se o servidor está em execução é invocar RpcEpResolveBinding, seguido por uma chamada para RpcMgmtIsServerListening. Para obter mais informações sobre o banco de dados do serviço de nomes, consulte The RPC Name Service Database.