Localizando sistemas de host do servidor

Um sistema de host do servidor é o computador que executa o programa de servidor do aplicativo distribuído. Pode haver um ou muitos sistemas de host de servidor em uma rede. A forma como o programa cliente encontra um servidor ao qual se conectar depende das necessidades do programa.

Há dois métodos para localizar sistemas de host do 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.
  • Consultar um banco de dados de serviço de nome para o local de um programa de servidor.

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

Usando associações de cadeia de caracteres

Os aplicativos podem criar associações a partir de informações armazenadas em cadeias de caracteres. Seu aplicativo cliente compõe essas informações como uma cadeia de caracteres e, em seguida, chama 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 inseridas. 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 associaçã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 literal apareçam na estrutura de dados de associação de cadeia de caracteres após 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 associação:

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

Uma função de conveniência, RpcStringBindingCompose , monta o objeto UUID, sequência de protocolo, endereço de rede e ponto de extremidade na sintaxe correta para a chamada para RpcBindingFromStringBinding. Você não precisa se preocupar em colocar o e comercial, dois-pontos e os vários componentes para cada sequência de protocolo no lugar certo; basta fornecer as cadeias de caracteres como parâmetros para a função . A biblioteca em tempo de execução aloca até mesmo 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, usa um identificador de associação como entrada e produz a associação de cadeia de caracteres correspondente.

Importando de bancos de dados de serviço de nome

Os bancos de dados de serviço de nome armazenam, entre outras coisas, identificadores de associação e UUIDs. Seu aplicativo cliente pode pesquisar por um ou ambos quando precisar se associar ao servidor. Para obter uma discussão sobre as informações que um serviço de nome armazena e o formato de armazenamento, consulte O Banco de Dados de Serviço de Nome RPC.

A biblioteca RPC fornece dois conjuntos de funções que seu programa cliente pode usar para pesquisar o banco de dados de serviço de nome. 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 associaçã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 de serviço de nome, elas precisam de um local para iniciar a pesquisa. Na terminologia RPC, isso é chamado de nome de entrada. O programa cliente passa o nome da entrada como o segundo parâmetro para RpcNsBindingImportBegin. Esse parâmetro poderá ser NULL se você quiser pesquisar o banco de dados de serviço de nome inteiro. Como alternativa, você pode pesquisar a entrada do servidor passando um nome de entrada de servidor ou pesquisando a entrada do grupo passando 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, essa é a única sintaxe de nome de entrada com suporte.

Seu aplicativo cliente pode pesquisar no banco de dados de serviço de nome um nome de interface, um UUID ou ambos. Se você quiser que ele pesquise uma interface por nome, passe a variável de interface global que o compilador MIDL gera do 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 o programa cliente pesquise apenas por UUID, defina o terceiro parâmetro como NULL.

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

A função RpcNsBindingImportBegin passa o endereço de um identificador de contexto de pesquisa de serviço de nome por meio 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 associação compatíveis do banco de dados de serviço de nome. 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 associação, seu aplicativo cliente poderá determinar se o identificador recebido é aceitável. Caso contrário, o programa cliente poderá 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 for concluída, chame a função RpcNsBindingImportDone para liberar o contexto de pesquisa.

Depois que o aplicativo cliente tiver um identificador de associação aceitável, ele deverá marcar para garantir que o aplicativo de servidor esteja 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 de 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 de serviço de nome, consulte O Banco de Dados de Serviço de Nome RPC.