Búsqueda de sistemas host de servidor

Un sistema host de servidor es el equipo que ejecuta el programa de servidor de la aplicación distribuida. Puede haber uno o varios sistemas host de servidor en una red. La forma en que el programa cliente encuentra un servidor al que conectarse depende de las necesidades del programa.

Hay dos métodos para buscar sistemas host de servidor:

  • Uso de información almacenada en cadenas en el código fuente del cliente, variables de entorno o archivos de configuración específicos de la aplicación. La aplicación cliente puede usar los datos de la cadena para componer un enlace entre el cliente y el servidor.
  • Consulta de una base de datos de servicio de nombres para la ubicación de un programa de servidor.

En esta sección se presenta información sobre ambas técnicas en los temas siguientes:

Uso de enlaces de cadena

Las aplicaciones pueden crear enlaces a partir de información almacenada en cadenas. La aplicación cliente compone esta información como una cadena y, a continuación, llama a la función RpcBindingFromStringBinding . El cliente debe proporcionar la siguiente información para identificar el servidor:

(El UUID de objeto y la información del punto de conexión son opcionales).

En los ejemplos siguientes, el parámetro pszNetworkAddress y otros parámetros incluyen barras diagonales inversas incrustadas. La barra diagonal inversa es un carácter de escape en el lenguaje de programación C. Se necesitan dos barras diagonales inversas para representar cada carácter de barra diagonal inversa de literal único. La estructura de enlace de cadena debe contener cuatro caracteres de barra diagonal inversa para representar los dos caracteres de barra diagonal inversa literales que preceden al nombre del servidor.

En el ejemplo siguiente se muestra que el nombre del servidor debe ir precedido de ocho barras diagonales inversas para que aparezcan cuatro caracteres de barra diagonal inversa literales en la estructura de datos de enlace de cadenas después de que la función sprintf_s procese la cadena.

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

En el ejemplo siguiente, el enlace de cadena aparece como:

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

A continuación, el cliente llama a RpcBindingFromStringBinding para obtener el identificador de enlace:

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

Una función de conveniencia, RpcStringBindingCompose ensambla el UUID de objeto, la secuencia de protocolo, la dirección de red y el punto de conexión en la sintaxis correcta para la llamada a RpcBindingFromStringBinding. No tiene que preocuparse por colocar los ampersand, los dos puntos y los distintos componentes para cada secuencia de protocolo en el lugar correcto; solo debe proporcionar las cadenas como parámetros a la función . La biblioteca en tiempo de ejecución incluso asigna la memoria necesaria para el enlace de cadena.

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

Otra función de conveniencia, RpcBindingToStringBinding, toma un identificador de enlace como entrada y genera el enlace de cadena correspondiente.

Importación desde bases de datos de servicio de nombres

Las bases de datos de servicio de nombres almacenan, entre otras cosas, identificadores de enlace e UUID. La aplicación cliente puede buscar o ambas cuando necesite enlazarse al servidor. Para obtener una explicación de la información que almacena un servicio de nombres y el formato de almacenamiento, consulte La base de datos del servicio de nombres RPC.

La biblioteca RPC proporciona dos conjuntos de funciones que el programa cliente puede usar para buscar en la base de datos del servicio de nombres. Los nombres de un conjunto comienzan por RpcNsBindingImport. Los nombres del otro conjunto comienzan por RpcNsBindingLookup. La diferencia entre los dos grupos de funciones es que las funciones RpcNsBindingImport devuelven un único identificador de enlace por llamada y las funciones RpcNsBindingLookup devuelven grupos de identificadores por llamada.

Para comenzar una búsqueda con las funciones RpcNsBindingImport, llame primero a RpcNsBindingImportBegin, como se muestra en el siguiente fragmento de código.

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

Cuando las funciones RPC buscan en la base de datos del servicio de nombres, necesitan un lugar para iniciar la búsqueda. En la terminología de RPC, se denomina nombre de entrada. El programa cliente pasa el nombre de entrada como segundo parámetro a RpcNsBindingImportBegin. Este parámetro puede ser NULL si desea buscar en toda la base de datos del servicio de nombres. Como alternativa, puede buscar en la entrada del servidor pasando un nombre de entrada de servidor o buscar en la entrada de grupo pasando un nombre de entrada de grupo. Pasar un nombre de entrada restringe la búsqueda al contenido de esa entrada.

En el ejemplo anterior, el valor RPC_C_NS_SYNTAX_DEFAULT se pasa como primer parámetro a RpcNsBindingImportBegin. Esto selecciona la sintaxis de nombre de entrada predeterminada. Actualmente, esta es la única sintaxis de nombre de entrada admitida.

La aplicación cliente puede buscar en la base de datos del servicio de nombres un nombre de interfaz, un UUID o ambos. Si desea que busque una interfaz por nombre, pase la variable de interfaz global que el compilador MIDL genera a partir del archivo IDL como tercer parámetro a RpcNsBindingImportBegin. Encontrará su declaración en el archivo de encabezado que generó el compilador MIDL cuando generó el código auxiliar del cliente. Si desea que el programa cliente busque solo por UUID, establezca el tercer parámetro en NULL.

Al buscar en la base de datos del servicio de nombres un UUID, establezca el cuarto parámetro de RpcNsBindingImportBegin en el UUID que desea buscar. Si no busca un UUID, establezca este parámetro en NULL.

La función RpcNsBindingImportBegin pasa la dirección de un identificador de contexto de búsqueda del servicio de nombres a través de su quinto parámetro. Este parámetro se pasa a otras funciones RpcNsBindingImport.

En concreto, la siguiente función a la que llamaría la aplicación cliente es RpcNsBindingImportNext. Los programas cliente usan esta función para recuperar identificadores de enlace compatibles de la base de datos del servicio de nombres. En el fragmento de código siguiente se muestra cómo se podría llamar a esta función:

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

Una vez que haya llamado a la función RpcNsBindingImportNext para obtener un identificador de enlace, la aplicación cliente puede determinar si el identificador recibido es aceptable. Si no es así, el programa cliente puede ejecutar un bucle y llamar a RpcNsBindingImportNext de nuevo para ver si el servicio de nombres contiene un identificador más adecuado. Para cada llamada a RpcNsBindingImportNext, debe haber una llamada correspondiente a RpcNsBindingFree. Una vez completada la búsqueda, llame a la función RpcNsBindingImportDone para liberar el contexto de búsqueda.

Una vez que la aplicación cliente tenga un identificador de enlace aceptable, debe comprobar que la aplicación de servidor se está ejecutando. Hay dos métodos que el cliente puede usar para realizar esta comprobación. La primera es llamar a una función en la interfaz de cliente. Si el programa de servidor se está ejecutando, se completará la llamada. Si no es así, se producirá un error en la llamada. Una mejor manera de comprobar que el servidor se está ejecutando es invocar RpcEpResolveBinding, seguido de una llamada a RpcMgmtIsServerListening. Para obtener más información sobre la base de datos de servicio de nombres, vea La base de datos del servicio de nombres RPC.