Lecciones de informática

RPC, Mensajería, REST: Terminología. Solución: el servicio "Llamada a procedimiento remoto (RPC)" no se inicia.

Conferencia 4

4.1 Concepto de llamada a procedimiento remoto

La idea de llamar a procedimientos remotos (Llamada a Procedimiento Remoto - RPC) Consiste en extender el mecanismo bien conocido y comprendido para transferir control y datos dentro de un programa que se ejecuta en una máquina para transferir control y datos a través de una red. Las herramientas de llamada a procedimientos remotos están diseñadas para facilitar la organización de la informática distribuida. La mayor eficiencia del uso de RPC se logra en aquellas aplicaciones en las que existe comunicación interactiva entre componentes remotos con tiempos de respuesta rápidos y una cantidad relativamente pequeña de datos transferidos. Estas aplicaciones se denominan orientadas a RPC.

Los rasgos característicos de la convocatoria de procedimientos locales son: asimetría, es decir, una de las partes que interactúan es el iniciador; sincronicidad, es decir, la ejecución del procedimiento que llama se detiene desde el momento en que se emite la solicitud y se reanuda solo después de que regresa el procedimiento llamado.

Implementar llamadas remotas es mucho más complicado que implementar llamadas a procedimientos locales. Para empezar, dado que los procedimientos llamados y llamados se ejecutan en máquinas diferentes, tienen diferentes espacios de direcciones, y esto crea problemas al pasar parámetros y resultados, especialmente si las máquinas no son idénticas. Dado que RPC no puede depender de la memoria compartida, esto significa que los parámetros de RPC no deben contener punteros a ubicaciones de memoria que no sean de pila y que los valores de los parámetros deben copiarse de una computadora a otra. La siguiente diferencia entre RPC y una llamada local es que necesariamente utiliza el sistema de comunicación subyacente, pero esto no debería ser explícitamente visible ni en la definición de los procedimientos ni en los procedimientos mismos. La lejanía introduce problemas adicionales. La ejecución del programa que llama y el procedimiento local llamado en la misma máquina se implementa dentro de un solo proceso. Pero la implementación de RPC implica al menos dos procesos: uno en cada máquina. Si uno de ellos falla, pueden surgir las siguientes situaciones: si el procedimiento de llamada falla, los procedimientos llamados remotamente quedarán “huérfanos”, y si los procedimientos remotos fallan, los procedimientos de llamada quedarán “padres huérfanos”, esperando en vano una respuesta de los procedimientos remotos.

Además, existen una serie de problemas asociados con la heterogeneidad de los lenguajes de programación y los entornos operativos: las estructuras de datos y las estructuras de llamadas a procedimientos admitidas en cualquier lenguaje de programación no lo son de la misma manera en todos los demás lenguajes.


Estos y algunos otros problemas se resuelven mediante la extendida tecnología RPC, que subyace a muchos sistemas operativos distribuidos.

Operaciones RPC básicas

Para comprender cómo funciona RPC, primero consideremos realizar una llamada a un procedimiento local en una máquina típica que se ejecuta sin conexión. Sea esto, por ejemplo, una llamada al sistema.

contar=leer(fd,buf,nbytes);

donde fd es un número entero;

buf – conjunto de caracteres;

nbytes es un número entero.

Para realizar la llamada, el procedimiento de llamada inserta los parámetros en la pila en orden inverso. Después de ejecutar la llamada de lectura, coloca el valor de retorno en un registro, mueve la dirección de retorno y devuelve el control al procedimiento de llamada, que extrae los parámetros de la pila y los devuelve a su estado original. Tenga en cuenta que en el lenguaje C, los parámetros se pueden llamar por referencia (por nombre) o por valor (por valor). En relación con el procedimiento llamado, los parámetros de valor son variables locales inicializadas. El procedimiento llamado puede cambiarlos sin afectar los valores originales de estas variables en el procedimiento que llama.

Si se pasa un puntero a una variable al procedimiento llamado, cambiar el valor de esta variable por el procedimiento llamado implica cambiar el valor de esta variable para el procedimiento que llama. Este hecho es muy significativo para RPC.

También hay otro mecanismo de paso de parámetros que no se utiliza en C. Se llama llamada por copia/restauración, que requiere que la persona que llama copie las variables en la pila como valores y luego las copie nuevamente después de realizar la llamada a través del valores originales del procedimiento de llamada.

La decisión sobre qué mecanismo de paso de parámetros utilizar la toman los desarrolladores del lenguaje. A veces depende del tipo de datos que se transfieren. En C, por ejemplo, los números enteros y otros datos escalares siempre se pasan por valor y las matrices siempre se pasan por referencia.

La idea detrás de RPC es hacer que una llamada a un procedimiento remoto se parezca lo más posible a una llamada a un procedimiento local. En otras palabras, haga que RPC sea transparente: el procedimiento que llama no necesita saber que el procedimiento llamado está en otra máquina, y viceversa.

RPC logra la transparencia de la siguiente manera. Cuando el procedimiento llamado es realmente remoto, se coloca en la biblioteca otra versión del procedimiento, denominada código auxiliar de cliente, en lugar del procedimiento local. Al igual que el procedimiento original, el stub se llama mediante una secuencia de llamada y se produce una interrupción al acceder al kernel. Sólo que, a diferencia del procedimiento original, no coloca parámetros en los registros y no solicita datos del kernel; en cambio, genera un mensaje para ser enviado al kernel de la máquina remota.

Etapas de ejecución de RPC

La interacción de los componentes del software al realizar una llamada a un procedimiento remoto se ilustra en la Figura 2.

Figura 2. Llamada a procedimiento remoto

Una vez que el programa cliente ha llamado al código auxiliar del cliente, su primera tarea es llenar el búfer con el mensaje que se envía. En algunos sistemas, el código auxiliar del cliente tiene un único búfer de longitud fija que se llena desde el principio con cada nueva solicitud. En otros sistemas, el búfer de mensajes es un conjunto de búferes para campos de mensajes individuales, algunos de los cuales ya están llenos. Este método es especialmente adecuado para casos en los que el paquete tiene un formato que consta de una gran cantidad de campos, pero los valores de muchos de estos campos no cambian de una llamada a otra.

Luego, los parámetros deben convertirse al formato apropiado e insertarse en el búfer de mensajes. En este punto, el mensaje está listo para ser enviado, por lo que se ejecuta la interrupción de la llamada del kernel.

Cuando el kernel obtiene el control, cambia de contexto, guarda los registros del procesador y el mapa de memoria (identificadores de página) e instala un nuevo mapa de memoria que se utilizará para ejecutar en modo kernel. Debido a que los contextos del kernel y del usuario son diferentes, el kernel debe copiar el mensaje exactamente en su propio espacio de direcciones para poder acceder a él, recordar la dirección de destino (y posiblemente otros campos de encabezado) y debe pasarlo a la interfaz de red. Esto completa el trabajo en el lado del cliente. El temporizador de transmisión está activado y el núcleo puede sondear cíclicamente una respuesta o pasar el control al programador, que seleccionará algún otro proceso para ejecutar. En el primer caso, la ejecución de consultas se acelera, pero no hay multiprogramación.

En el lado del servidor, el hardware receptor coloca los bits entrantes en un búfer en el chip o en la RAM. Cuando se ha recibido toda la información, se genera una interrupción. El manejador de interrupciones verifica la exactitud de los datos del paquete y determina a qué código auxiliar se debe enviar. Si ninguno de los resguardos espera este paquete, el controlador debe almacenarlo en el buffer o descartarlo por completo. Si hay un resguardo en espera, el mensaje se copia en él. Finalmente se realiza un cambio de contexto, mediante el cual se restauran los registros y el mapa de memoria, tomando los valores que tenían en el momento en que el stub realizó la llamada de recepción.

Ahora el código auxiliar del servidor comienza a funcionar. Desempaqueta los parámetros y los coloca adecuadamente en la pila. Cuando todo está listo se realiza una llamada al servidor. Después de ejecutar el procedimiento, el servidor transmite los resultados al cliente. Para hacer esto, realice todos los pasos descritos anteriormente, solo que en orden inverso.

La Figura 3 muestra la secuencia de comandos que se deben ejecutar para cada llamada RPC.

Figura 3. Pasos del procedimiento RPC

Llamada a procedimiento remoto(o Llamar a procedimientos remotos) (De inglés. Llamada a procedimiento remoto (RPC)): una clase de tecnologías que permiten que los programas de computadora llamen a funciones o procedimientos en otro espacio de direcciones (generalmente en computadoras remotas). Normalmente, una implementación de la tecnología RPC incluye dos componentes: un protocolo de red para la comunicación cliente-servidor y un lenguaje de serialización de objetos (o estructuras, para RPC que no es de objetos). Las diferentes implementaciones de RPC tienen arquitecturas muy diferentes y varían en sus capacidades: algunas implementan la arquitectura SOA, otras CORBA o DCOM. En la capa de transporte, los RPC utilizan principalmente los protocolos TCP y UDP; sin embargo, algunos están construidos sobre HTTP (lo que viola la arquitectura ISO/OSI, ya que HTTP no es un protocolo de transporte nativo).

Implementaciones

Existen muchas tecnologías que proporcionan RPC:

  • Sun RPC (protocolo binario basado en TCP, UDP y XDR) RFC-1831 segundo nombre ONC RPC RFC-1833
  • .Net Remoting (protocolo binario basado en TCP, UDP, HTTP)
  • SOAP: Protocolo simple de acceso a objetos (protocolo de texto basado en HTTP), consulte la especificación: RFC-4227
  • XML RPC (protocolo de texto basado en HTTP) consulte la especificación: RFC-3529
  • Java RMI: invocación de método remoto de Java; consulte la especificación: http://java.sun.com/j2se/1.5.0/docs/guide/rmi/index.html
  • JSON-RPC Llamadas a procedimientos remotos de notación de objetos JavaScript (protocolo de texto basado en HTTP) consulte la especificación: RFC-4627
  • DCE/RPC: entorno informático distribuido/llamadas a procedimientos remotos (protocolo binario basado en varios protocolos de transporte, incluidos TCP/IP y Named Pipes del protocolo SMB/CIFS)
  • DCOM: modelo de objetos componentes distribuido conocido como MSRPC llamada a procedimiento remoto de Microsoft o "Network OLE" (una extensión orientada a objetos de DCE RPC que le permite pasar referencias a objetos y llamar a métodos de objetos a través de dichas referencias)

Principio

La idea de una llamada a procedimiento remoto (RPC) es ampliar el mecanismo bien conocido y comprendido para transferir control y datos dentro de un programa que se ejecuta en una máquina para transferir control y datos a través de una red. Las herramientas de llamada a procedimientos remotos están diseñadas para facilitar la organización de la informática distribuida y la creación de sistemas de información distribuidos cliente-servidor. La mayor eficiencia del uso de RPC se logra en aquellas aplicaciones en las que existe comunicación interactiva entre componentes remotos con tiempos de respuesta rápidos y una cantidad relativamente pequeña de datos transferidos. Estas aplicaciones se denominan orientadas a RPC.

Implementar llamadas remotas es mucho más complicado que implementar llamadas a procedimientos locales. Podemos identificar los siguientes problemas y tareas que deben resolverse al implementar RPC:

  • Debido a que los procedimientos llamados y llamados se ejecutan en máquinas diferentes, tienen espacios de direcciones diferentes, y esto crea problemas al pasar parámetros y resultados, especialmente si las máquinas ejecutan sistemas operativos diferentes o tienen arquitecturas diferentes (por ejemplo, little-endian o big-endian). endian). ). Dado que RPC no puede depender de la memoria compartida, esto significa que los parámetros de RPC no deben contener punteros a ubicaciones de memoria que no sean de pila y que los valores de los parámetros deben copiarse de una computadora a otra. Para copiar los parámetros del procedimiento y los resultados de la ejecución a través de la red, se serializan.
  • A diferencia de una llamada local, una llamada a procedimiento remoto utiliza necesariamente la capa de transporte de la arquitectura de red (por ejemplo, TCP), pero esto permanece oculto para el desarrollador.
  • La ejecución del programa que llama y el procedimiento local llamado en la misma máquina se implementa dentro de un solo proceso. Pero la implementación de RPC implica al menos dos procesos: uno en cada máquina. Si uno de ellos falla, pueden surgir las siguientes situaciones: si el procedimiento que llama falla, los procedimientos llamados remotamente quedarán “huérfanos”, y si los procedimientos remotos fallan, los procedimientos que llaman se convertirán en “padres indigentes”, que esperarán en vano para una respuesta de los procedimientos remotos.
  • Hay una serie de problemas asociados con la heterogeneidad de los lenguajes de programación y los entornos operativos: las estructuras de datos y las estructuras de llamadas a procedimientos admitidas en cualquier lenguaje de programación no lo son de la misma manera en todos los demás lenguajes. Por tanto, existe un problema de compatibilidad que aún no se ha resuelto ni mediante la introducción de un estándar generalmente aceptado ni mediante la implementación de varios estándares competitivos en todas las arquitecturas y en todos los lenguajes.

Subsistemas

  • Subsistema de transporte

Gestionar conexiones salientes y entrantes. - soporte para el concepto de "límite de mensaje" para protocolos de transporte que no lo soportan directamente (TCP). - soporte para entrega garantizada para protocolos de transporte que no lo admiten directamente (UDP).

  • Grupo de subprocesos (solo destinatario). Proporciona un contexto de ejecución para el código invocado a través de la red.
  • Marshalling (también llamado "serialización"). Empaquetar parámetros de llamada en un flujo de bytes de forma estándar, independientemente de la arquitectura (en particular, el orden de los bytes en una palabra). En particular, puede afectar matrices, cadenas y estructuras a las que apuntan parámetros de puntero.
  • Cifrar paquetes y aplicarles una firma digital.
  • Autenticacion y autorizacion. Transmisión a través de la red de información que identifica al sujeto que realiza la llamada.

En algunas implementaciones de RPC (.NET Remoting), los límites de los subsistemas son interfaces polimórficas abiertas y es posible escribir su propia implementación de casi todos los subsistemas enumerados. En otras implementaciones (DCE RPC en Windows) este no es el caso.

ver también

Concepto de llamada a procedimiento remoto (RPC)

La idea de una llamada a procedimiento remoto (RPC) es ampliar el mecanismo bien conocido y comprendido para transferir control y datos dentro de un programa que se ejecuta en una máquina para transferir control y datos a través de una red. Las herramientas de llamada a procedimientos remotos están diseñadas para facilitar la organización de la informática distribuida. La mayor eficiencia del uso de RPC se logra en aquellas aplicaciones en las que existe comunicación interactiva entre componentes remotos con tiempos de respuesta rápidos y una cantidad relativamente pequeña de datos transferidos. Estas aplicaciones se denominan orientadas a RPC.

Los rasgos característicos de la convocatoria de trámites locales son:

  • Asimetría, es decir, una de las partes que interactúan es el iniciador;
  • Sincronicidad, es decir, la ejecución del procedimiento que llama se suspende desde el momento en que se emite la solicitud y se reanuda solo después de que regresa el procedimiento llamado.

Implementar llamadas remotas es mucho más complicado que implementar llamadas a procedimientos locales. Para empezar, dado que los procedimientos llamados y llamados se ejecutan en máquinas diferentes, tienen diferentes espacios de direcciones, y esto crea problemas al pasar parámetros y resultados, especialmente si las máquinas no son idénticas. Dado que RPC no puede depender de la memoria compartida, esto significa que los parámetros de RPC no deben contener punteros a ubicaciones de memoria que no sean de pila y que los valores de los parámetros deben copiarse de una computadora a otra. La siguiente diferencia entre RPC y una llamada local es que necesariamente utiliza el sistema de comunicación subyacente, pero esto no debería ser explícitamente visible ni en la definición de los procedimientos ni en los procedimientos mismos. La lejanía introduce problemas adicionales. La ejecución del programa que llama y el procedimiento local llamado en la misma máquina se implementa dentro de un solo proceso. Pero la implementación de RPC implica al menos dos procesos: uno en cada máquina. Si uno de ellos falla, pueden surgir las siguientes situaciones: si el procedimiento de llamada falla, los procedimientos llamados remotamente quedarán “huérfanos”, y si los procedimientos remotos fallan, los procedimientos de llamada quedarán “padres huérfanos”, esperando en vano una respuesta de los procedimientos remotos.

Además, existen una serie de problemas asociados con la heterogeneidad de los lenguajes de programación y los entornos operativos: las estructuras de datos y las estructuras de llamadas a procedimientos admitidas en cualquier lenguaje de programación no lo son de la misma manera en todos los demás lenguajes.

Estos y algunos otros problemas se resuelven mediante la extendida tecnología RPC, que subyace a muchos sistemas operativos distribuidos. Operaciones RPC básicas

Para comprender cómo funciona RPC, primero consideremos realizar una llamada a un procedimiento local en una máquina típica que se ejecuta sin conexión. Sea esto, por ejemplo, una llamada al sistema.

contar=leer(fd, buf, nbytes);

donde fd es un número entero, buf es una matriz de caracteres y nbytes es un número entero.

Para realizar la llamada, el procedimiento de llamada inserta los parámetros en la pila en orden inverso (Figura 3.1). Después de ejecutar la llamada de lectura, coloca el valor de retorno en un registro, mueve la dirección de retorno y devuelve el control al procedimiento de llamada, que extrae los parámetros de la pila y los devuelve a su estado original. Tenga en cuenta que en el lenguaje C, los parámetros se pueden llamar por referencia (por nombre) o por valor (por valor). En relación con el procedimiento llamado, los parámetros de valor son variables locales inicializadas. El procedimiento llamado puede cambiarlos sin afectar los valores originales de estas variables en el procedimiento que llama.

Si se pasa un puntero a una variable al procedimiento llamado, cambiar el valor de esta variable por el procedimiento llamado implica cambiar el valor de esta variable para el procedimiento que llama. Este hecho es muy significativo para RPC.

También hay otro mecanismo de paso de parámetros que no se utiliza en C. Se llama llamada por copia/restauración, que requiere que la persona que llama copie las variables en la pila como valores y luego las copie nuevamente después de realizar la llamada a través del valores originales del procedimiento de llamada.

La decisión sobre qué mecanismo de paso de parámetros utilizar la toman los desarrolladores del lenguaje. A veces depende del tipo de datos que se transfieren. En C, por ejemplo, los números enteros y otros datos escalares siempre se pasan por valor y las matrices siempre se pasan por referencia.

Solicitud

Una parte importante de las herramientas de administración remota del sistema operativo Windows (Visor de eventos, Administrador de servidores, administración de impresión, administración de listas de usuarios) utilizan DCE RPC como medio de comunicación de red entre el servicio administrado y la aplicación de administración de interfaz de usuario. El soporte DCE RPC ha estado presente en Windows NT desde la primera versión 3.1. Los clientes DCE RPC también fueron compatibles con la línea ligera de sistemas operativos Windows 3.x/95/98/Me.

Las bibliotecas del sistema Windows que proporcionan dichas capacidades de control y sirven como capa base para aplicaciones de control de interfaz de usuario (netapi32.dll y en parte advapi32.dll) en realidad contienen código de cliente para las interfaces DCE RPC que realizan este control.

Esta decisión arquitectónica fue objeto de críticas activas contra Microsoft. Los procedimientos de clasificación genéricos presentes en DCE RPC son muy complejos y tienen un enorme potencial para explotar defectos en la red mediante el envío de un paquete DCE RPC deliberadamente mal formado. Una parte importante de los defectos de seguridad de Windows descubiertos desde finales de los 90 hasta mediados de los 2000 fueron errores en el código de clasificación DCE RPC.

Además de DCE RPC, Windows utiliza activamente la tecnología DCOM. Por ejemplo, se utiliza como medio de comunicación entre las herramientas de administración del servidor web IIS y el propio servidor que se administra. Una interfaz completamente funcional para comunicarse con el sistema de correo MS Exchange Server (MAPI) también se basa en DCOM.

El propósito de este artículo es discutir la terminología. El artículo no trata sobre cómo y por qué, sino sólo sobre el uso de la terminología. El artículo refleja la opinión del autor y no pretende ser científico.

Introducción

Si trabajas en programación sistemas distribuidos o en integración de sistemas, entonces la mayor parte de lo que se presenta aquí no es nuevo para usted.

El problema surge cuando personas que usan diferentes tecnologías se encuentran y cuando esas personas comienzan a tener conversaciones técnicas. En este caso, a menudo surgen malentendidos mutuos debido a la terminología. Aquí intentaré reunir las terminologías utilizadas en diferentes contextos.

Terminología

No existe una terminología ni una clasificación claras en esta área. La terminología utilizada a continuación es un reflejo del modelo del autor, es decir, es estrictamente subjetiva. Cualquier crítica y discusión son bienvenidas.

He dividido la terminología en tres áreas: RPC (llamada a procedimiento remoto), mensajería y REST. Estas áreas tienen raíces históricas.

RPC

RPC tecnologías: las tecnologías más antiguas. Los representantes más destacados de RPC son: CORBA Y DCOM.

En aquella época, la mayoría de los sistemas debían conectarse a través de redes locales rápidas y relativamente fiables. La idea principal detrás de RPC era hacer que llamar a sistemas remotos fuera muy parecido a llamar a funciones dentro de un programa. Toda la mecánica de las llamadas remotas estaba oculta al programador. Al menos intentaron ocultarlo. En muchos casos, los programadores se vieron obligados a trabajar en un nivel más profundo, donde aparecieron los términos marshaling ( ordenar) Y desmantelando(¿Cómo es eso en ruso?), que esencialmente significaba serialización. Las llamadas a funciones normales dentro de los procesos se manejaban al final de la persona que llama en Apoderado, y en el lado del sistema que realiza la función, en Despachador. Idealmente, ni el sistema de llamadas ni el sistema de procesamiento se ocuparían de las complejidades de la transferencia de datos entre sistemas. Todas estas sutilezas se concentraron en el paquete Proxy - Dispatcher, cuyo código se generó automáticamente.

Por lo tanto, no notará, no debería notar, ninguna diferencia entre llamar a una función local y llamar a una función remota.
Ahora hay una especie de renacimiento de RPC, cuyos representantes más destacados son: Google ProtoBuf, Thrift, Avro.

Mensajería

Con el tiempo, resultó que el intento de proteger al programador del hecho de que la función llamada aún difiere de la local no condujo al resultado deseado. Los detalles de implementación y las diferencias fundamentales entre los sistemas distribuidos eran demasiado grandes para resolverlos utilizando código Proxy generado automáticamente. Poco a poco, se comprendió que el hecho de que los sistemas estén conectados por un entorno poco fiable, lento y de baja velocidad debe reflejarse explícitamente en el código del programa.

Han aparecido tecnologías servicios web. empezamos a hablar ABC: Dirección, Vinculación, Contrato. No está del todo claro por qué aparecieron los contratos, que son esencialmente sobres para argumentos de entrada. Los contratos suelen complicar el modelo general en lugar de simplificarlo. Pero... no importa.

Ahora el programador creó explícitamente servicio(Servicio) o cliente(Cliente) llamando al servicio. El servicio consistió en un conjunto operaciones (Operación), cada uno de los cuales tomó en la entrada pedido(Pedido) y emitido respuesta(Respuesta). Cliente explícitamente enviado(Enviado) solicitud, el servicio recibido explícitamente ( Recibir) y le respondió (Enviado), enviando la respuesta. El cliente recibió respuesta y la llamada finalizó.

Al igual que en RPC, había un Proxy y un Dispatcher ejecutándose en alguna parte. Y como antes, su código se generaba automáticamente y el programador no necesitaba entenderlo. A menos que el cliente haya utilizado explícitamente clases de Proxy.

Las solicitudes y respuestas se convierten explícitamente a un formato destinado a la transmisión por cable. La mayoría de las veces se trata de una matriz de bytes. La transformación se llama Publicación por entregas Y Deserialización y a veces se esconde en el código Proxy.
La culminación de la mensajería se manifestó en el surgimiento del paradigma ESB (autobús de servicio empresarial). Nadie puede explicar realmente qué es, pero todos están de acuerdo en que los datos se mueven a través del ESB en forma de mensajes.

DESCANSAR

En la lucha constante con la complejidad del código, los programadores dieron el siguiente paso y crearon DESCANSAR.

El principio fundamental de REST es que las operaciones de funciones están muy limitadas y solo se deja un conjunto de operaciones. CRUD: Crear - Leer - Actualizar - Eliminar. En este modelo, todas las operaciones siempre se aplican a algunos datos. Las operaciones disponibles en CRUD son suficientes para la mayoría de las aplicaciones. Dado que las tecnologías REST en la mayoría de los casos implican el uso del protocolo HTTP, los comandos CRUD se reflejaron en los comandos. HTTP (Correo - Conseguir - Poner - Borrar) . Se afirma constantemente que REST no está necesariamente vinculado a HTTP. Pero en la práctica, se utiliza ampliamente la reflexión de las firmas de operación en la sintaxis de los comandos HTTP. Por ejemplo, llamando a la función

EntityAddress ReadEntityAddress (cadena parámetro1, cadena parámetro2)

Expresado así:

OBTENER: dirección de entidad?param1=valor1¶m2=valor2

Conclusión

Antes de comenzar una discusión sobre sistemas distribuidos o integración, defina la terminología. Si Proxy siempre significará lo mismo en diferentes contextos, entonces, por ejemplo, solicitud significará poco en términos de RPC, y la clasificación causará confusión cuando se hable de tecnologías REST.



Los programas que se comunican a través de una red necesitan un mecanismo de comunicación. En el nivel inferior, al llegar los paquetes, un programa de procesamiento de señales de red envía y procesa una señal. En el nivel superior funciona el mecanismo de encuentro adoptado en el idioma Ada. NFS utiliza un mecanismo de llamada a procedimiento remoto (RPC) en el que el cliente se comunica con el servidor (consulte la Figura 1). Según este proceso, el cliente primero llama a un procedimiento que envía una solicitud al servidor. Al llegar un paquete de solicitud, el servidor llama al procedimiento de apertura del paquete, realiza el servicio solicitado, envía una respuesta y el control regresa al cliente.

Se puede considerar que la interfaz RPC consta de tres capas:

  1. El nivel superior es completamente transparente. Un programa en este nivel puede, por ejemplo, contener una llamada al procedimiento rnusers(), que devuelve el número de usuarios en la máquina remota. No necesita saber cómo utilizar el mecanismo RPC ya que realiza la llamada en el programa.
  2. El nivel medio está destinado a las aplicaciones más comunes. Las llamadas RPC en este nivel son manejadas por las subrutinas Registerrpc() y callrpc(): Registerrpc() recibe código de todo el sistema y callrpc() ejecuta una llamada a procedimiento remoto. La llamada a rnusers() se implementa utilizando estas dos rutinas.
  3. El nivel inferior se utiliza para tareas más complejas que cambian los valores predeterminados de los parámetros del procedimiento. En este nivel, puede manipular explícitamente los sockets utilizados para transmitir mensajes RPC.

Como regla general, debes usar el nivel superior y evitar usar los niveles inferiores a menos que sea absolutamente necesario.

Aunque en este tutorial sólo consideramos la interfaz C, las llamadas a procedimientos remotos se pueden realizar desde cualquier idioma. El funcionamiento del mecanismo RPC para organizar la comunicación entre procesos en diferentes máquinas no es diferente de su funcionamiento en una máquina.

RPC (llamada a procedimiento remoto) es una interfaz entre usuarios remotos y ciertos programas host que se inician a pedido de estos usuarios. El servicio RPC de cualquier host suele proporcionar a los clientes un conjunto de programas. Cada uno de estos programas consta, a su vez, de uno o más procedimientos remotos. Por ejemplo, un servicio de sistema de archivos remoto NFS que se basa en llamadas RPC puede constar de solo dos programas: por ejemplo, un programa interactúa con interfaces de usuario de alto nivel y el otro con funciones de E/S de bajo nivel.

Cada llamada a procedimiento remoto involucra a dos partes: el cliente activo, que envía la solicitud de llamada al procedimiento al servidor, y el servidor, que envía la respuesta al cliente.

Nota. Debe tenerse en cuenta que los términos "cliente" y "servidor" en este caso se refieren a una transacción específica. Un host o software (proceso o programa) en particular puede actuar como cliente y como servidor. Por ejemplo, un programa que proporciona un servicio de procedimiento remoto puede al mismo tiempo ser un cliente para trabajar con un sistema de archivos de red.

El protocolo RPC se basa en un modelo de llamada a procedimiento remoto, similar al mecanismo de llamada a procedimiento local. Cuando llama a un procedimiento local, coloca argumentos en una ubicación específica en la memoria, la pila o las variables de entorno, y transfiere el control del proceso a una dirección específica. Una vez que se completa el trabajo, lee los resultados en una dirección específica y continúa con su proceso.

Cuando se trabaja con un procedimiento remoto, la principal diferencia es que la llamada a la función remota es manejada por dos procesos: un proceso cliente y un proceso servidor.

El proceso del cliente envía un mensaje al servidor, que incluye los parámetros del procedimiento llamado, y espera un mensaje de respuesta con los resultados de su trabajo. Cuando se recibe una respuesta, se lee el resultado y el proceso continúa. En el lado del servidor, el proceso del controlador de llamadas está en estado de espera y cuando llega un mensaje, lee los parámetros del procedimiento, lo ejecuta, envía una respuesta y queda en estado de espera para la siguiente llamada.

El protocolo RPC no impone ningún requisito de comunicación adicional entre procesos y no requiere sincronización de las funciones realizadas, es decir, las llamadas pueden ser asíncronas y mutuamente independientes, de modo que el cliente puede realizar otros procedimientos mientras espera una respuesta. El servidor RPC puede asignar un proceso o máquina virtual independiente para cada función, por lo tanto, sin esperar a que se completen las solicitudes anteriores, puede aceptar inmediatamente las siguientes.

Sin embargo, existen varias diferencias importantes entre las llamadas a procedimientos locales y remotos:

  1. Error de procesamiento. En cualquier caso, el cliente debería recibir notificaciones de los errores que se produzcan al llamar a procedimientos remotos en el servidor o la red.
  2. Variables globales. Debido a que el servidor no tiene acceso al espacio de direcciones del cliente, las llamadas a procedimientos remotos no pueden usar parámetros ocultos en forma de variables globales.
  3. Actuación. La velocidad de ejecución de procedimientos remotos suele ser uno o dos órdenes de magnitud menor que la velocidad de ejecución de procedimientos locales similares.
  4. Autenticación. Dado que las llamadas a procedimientos remotos se producen a través de la red, se deben utilizar mecanismos de autenticación del cliente.

Principios de construcción de protocolos.

El protocolo RPC puede utilizar varios protocolos de transporte diferentes. Las responsabilidades del protocolo RPC son únicamente proporcionar estándares e interpretar la transmisión de mensajes. La confiabilidad y confiabilidad de la transmisión de mensajes está completamente garantizada por la capa de transporte.

Sin embargo, RPC puede controlar la selección y algunas funciones del protocolo de transporte. Como ejemplo de la interacción entre RPC y el protocolo de transporte, considere el procedimiento para asignar un puerto RPC para que un proceso de aplicación funcione a través de RPC - Portmapper.

Esta función asigna dinámicamente (bajo demanda) una conexión RPC a un puerto específico. La función Portmapper se utiliza con bastante frecuencia porque el conjunto de puertos de transporte reservados para RPC es limitado y la cantidad de procesos que potencialmente pueden ejecutarse simultáneamente es muy alta. Portmapper, por ejemplo, se llama al seleccionar puertos para la interacción entre el cliente y el servidor del sistema NFS.

El servicio Portmapper utiliza un mecanismo para transmitir mensajes RPC a un puerto específico: III. El cliente envía un mensaje de difusión de solicitud de puerto para un servicio RPC específico a este puerto. El servicio Portmapper procesa el mensaje fiscal, determina la dirección del servicio RPC local y envía una respuesta al cliente. El servicio RPC Portmapper puede funcionar con protocolos TCP y UDP.

RPC puede funcionar con varios protocolos de transporte, pero nunca duplica sus funciones, es decir, si RPC se ejecuta sobre TCP, todas las preocupaciones sobre la confiabilidad y validez de la conexión RPC se asignan a TCP. Sin embargo, si el protocolo RPC se instala sobre UDP, puede proporcionar funciones adicionales propias para garantizar la entrega de mensajes.

Nota.

Las tareas de aplicación pueden considerar el protocolo RPC como un procedimiento específico para llamar a una función a través de la red JSR (Instrucción de subrutina de salto).

Para que el protocolo RPC funcione, se deben cumplir las siguientes condiciones:

  1. Identificación única de todos los procedimientos llamados remotamente en un host determinado. Las solicitudes RPC contienen tres campos de identificación: el número del programa remoto (servicio), el número de versión del programa remoto y el número del procedimiento remoto del programa especificado. El número de programa lo asigna el fabricante del servicio, el número de procedimiento indica la función específica de este servicio.
  2. Identificación de la versión del protocolo RPC. Los mensajes RPC contienen un campo de versión del protocolo RPC. Se utiliza para coordinar los formatos de los parámetros pasados ​​cuando el cliente trabaja con diferentes versiones de RPC.
  3. Proporcionar mecanismos de autenticación del cliente al servidor. El protocolo RPC proporciona un procedimiento para autenticar al cliente en el servicio y, si es necesario, cada vez que se realiza una solicitud o se envía una respuesta al cliente. Además, RPC permite el uso de varios mecanismos de seguridad adicionales.

RPC puede utilizar cuatro tipos de mecanismos de autenticación:

  • AUTH_NULL: no se requiere autenticación
  • AUTH_UNIX: autenticación según el estándar UNIX
  • AUTH_SHORT: autenticación estándar UNIX con su propia estructura de codificación
  • AUTH_DES: autenticación según el estándar DES
  1. Identificación de mensajes de respuesta a las solicitudes correspondientes. Los mensajes de respuesta RPC contienen el identificador de la solicitud a partir de la cual fueron construidos. Este identificador puede denominarse identificador de transacción de llamada RPC. Este mecanismo es especialmente necesario cuando se trabaja en modo asíncrono y cuando se realiza una secuencia de varias llamadas RPC.
  2. Identificación de errores de protocolo. Todos los errores de red o servidor tienen identificadores únicos, mediante los cuales cada uno de los participantes de la conexión puede determinar la causa del fallo.

Estructuras de mensajes de protocolo

Al enviar mensajes RPC a través de un protocolo de transporte, se pueden ubicar varios mensajes RPC dentro de un único paquete de transporte. Para separar un mensaje de otro, se utiliza un marcador de registro (RM - Record Marker). Cada mensaje RPC está "marcado" exactamente con un RM.

Un mensaje RPC puede constar de varios fragmentos. Cada fragmento consta de cuatro bytes de encabezado y datos (0 a 2**31-1). El primer bit del encabezado indica si el fragmento es el último y los 31 bits restantes indican la longitud del paquete de datos.

La estructura RPC se describe formalmente en el lenguaje para describir y representar formatos de datos: XDR con adiciones relacionadas con la descripción de procedimientos. Incluso se podría decir que el lenguaje de descripción RPC es una extensión de XDR, complementado con el trabajo con procedimientos.

La estructura del paquete RPC se ve así:


La estructura de respuesta (reply_body) puede contener una estructura de error (en cuyo caso contiene el código de error) o una estructura de procesamiento de solicitud exitosa (en cuyo caso contiene los datos devueltos).

Interfaz de software de alto nivel.

Usar subrutinas en un programa es una forma tradicional de estructurar una tarea y hacerla más clara. Las rutinas utilizadas con más frecuencia se recopilan en bibliotecas donde pueden ser utilizadas por varios programas. En este caso, estamos hablando de una llamada local (local), es decir, tanto el objeto que llama como el llamado funcionan dentro del mismo programa en la misma computadora.

En el caso de una llamada remota, un proceso que se ejecuta en una computadora inicia un proceso en la computadora remota (es decir, en realidad ejecuta el código de procedimiento en la computadora remota). Obviamente, una llamada a un procedimiento remoto difiere significativamente de una local tradicional, pero desde el punto de vista del programador, tales diferencias están prácticamente ausentes, es decir, la arquitectura de una llamada a un procedimiento remoto le permite simular una llamada a un procedimiento local.

Sin embargo, si en el caso de una llamada local el programa pasa parámetros al procedimiento llamado y recibe el resultado del trabajo a través de la pila o áreas de memoria compartida, entonces en el caso de una llamada remota la transferencia de parámetros se convierte en la transmisión de una solicitud a través de la red, y el resultado del trabajo está en la respuesta recibida.

Este enfoque es una posible base para crear aplicaciones distribuidas y, aunque muchos sistemas modernos no utilizan este mecanismo, en muchos casos se conservan los conceptos y términos básicos. Al describir el mecanismo RPC, tradicionalmente llamaremos cliente al proceso de llamada y servidor al proceso remoto que implementa el procedimiento.

Una llamada a procedimiento remoto implica los siguientes pasos:

  1. El programa cliente realiza una llamada local a un procedimiento llamado stub. En este caso, el cliente "parece" que al llamar al código auxiliar, en realidad está llamando al procedimiento del servidor. De hecho, el cliente pasa los parámetros necesarios al código auxiliar y devuelve el resultado. Sin embargo, las cosas no son exactamente como el cliente imagina. El trabajo del stub es aceptar los argumentos destinados al procedimiento remoto, posiblemente convertirlos a algún formato estándar y formular una solicitud de red. Empaquetar los argumentos y crear la solicitud de red se denomina marshalling.
  2. La solicitud de red se reenvía a través de la red al sistema remoto. Para hacer esto, el código auxiliar utiliza llamadas apropiadas, por ejemplo, las analizadas en las secciones anteriores. Tenga en cuenta que se pueden utilizar varios protocolos de transporte, y no sólo la familia TCP/IP.
  3. En el host remoto, todo sucede en orden inverso. El código auxiliar del servidor escucha una solicitud y, al recibirla, recupera los parámetros (los argumentos de la llamada al procedimiento). La descomposición puede implicar transformaciones necesarias (por ejemplo, cambios en el orden de los bytes).
  4. El stub realiza una llamada al procedimiento del servidor real al que se dirige la solicitud del cliente, pasándole los argumentos recibidos a través de la red.
  5. Una vez completado el procedimiento, el control regresa al código auxiliar del servidor y le pasa los parámetros requeridos. Como el talón del cliente; El código auxiliar del servidor convierte los valores devueltos por el procedimiento, generando un mensaje de respuesta de red que se transmite a través de la red al sistema del que proviene la solicitud.
  6. El sistema operativo pasa el mensaje recibido al stub del cliente, que, después de la transformación necesaria, pasa los valores (que son los valores devueltos por el procedimiento remoto) al cliente, que trata esto como un retorno normal del procedimiento.

Así, desde el punto de vista del cliente, realiza una llamada a un procedimiento remoto como lo haría con uno local. Lo mismo puede decirse del servidor: un procedimiento se llama de forma estándar, un determinado objeto (stub del servidor) llama a un procedimiento local y recibe los valores devueltos por él. El cliente trata el stub como un procedimiento de servidor invocable y el servidor trata su propio stub como un cliente.

Por lo tanto, los stubs forman el núcleo del sistema RPC, responsables de todos los aspectos de la generación y transmisión de mensajes entre el cliente y el servidor remoto (procedimiento), aunque tanto el cliente como el servidor creen que las llamadas se producen localmente. Este es el concepto básico de RPC: ocultar completamente la naturaleza distribuida (de red) de la interacción en el código auxiliar. Las ventajas de este enfoque son obvias: tanto el cliente como el servidor son independientes de la implementación de la red, ambos operan dentro de una máquina virtual distribuida y las llamadas a procedimientos tienen una interfaz estándar.

Pasando parámetros

Pasar parámetros de valor no causa ninguna dificultad particular. En este caso, el código auxiliar del cliente coloca el valor del parámetro en la solicitud de red, posiblemente realizando conversiones al formato estándar (por ejemplo, invirtiendo el orden de los bytes). La situación es mucho más complicada con el paso de punteros, cuando el parámetro representa la dirección de los datos y no su valor. Pasar la dirección en la solicitud no tiene sentido, ya que el procedimiento remoto se ejecuta en un espacio de direcciones completamente diferente. La solución más simple utilizada en RPC es prohibir a los clientes pasar parámetros que no sean por valor, aunque esto, por supuesto, impone serias restricciones.

Vinculante

Antes de que un cliente pueda llamar a un procedimiento remoto, debe estar asociado con un sistema remoto que aloje el servidor requerido. Así, la tarea vinculante se divide en dos:

  1. Encontrar un host remoto con el servidor requerido
  2. Encontrar el proceso de servidor requerido en un host determinado

Se pueden utilizar varios enfoques para encontrar el anfitrión. Una posible opción es crear algún tipo de directorio centralizado en el que los hosts anuncien sus servidores y donde el cliente, si lo desea, pueda seleccionar el host y la dirección del procedimiento que más le convengan.

Cada procedimiento RPC se identifica de forma única mediante un número de programa y procedimiento. El número de programa identifica un grupo de procedimientos remotos, cada uno de los cuales tiene su propio número. A cada programa también se le asigna un número de versión, de modo que si realiza cambios menores en el programa (por ejemplo, agregando un procedimiento), no es necesario cambiar su número. Normalmente, se implementan varios procedimientos funcionalmente similares en un módulo de software que, cuando se inicia, se convierte en el servidor de estos procedimientos y se identifica por el número de programa.

Así, cuando un cliente quiere llamar a un procedimiento remoto, necesita conocer el programa, la versión y los números de procedimiento que brindan el servicio requerido.

Para transmitir una solicitud, el cliente también necesita conocer la dirección de red del host y el número de puerto asociado con el programa del servidor que proporciona los procedimientos requeridos. Para esto se utiliza el demonio portmap(IM) (llamado rpcbind(IM) en algunos sistemas). El demonio se ejecuta en el host que proporciona el servicio de procedimiento remoto y utiliza un número de puerto conocido. Cuando se inicializa un proceso de servidor, registra sus procedimientos y números de puerto en portmap (IM). Ahora, cuando un cliente necesita saber el número de puerto para llamar a un procedimiento específico, envía una solicitud al servidor portmap(IM), que a su vez devuelve el número de puerto o reenvía la solicitud directamente al servidor de procedimiento remoto y, después al ejecutarlo, devuelve una respuesta al cliente. En cualquier caso, si existe el procedimiento requerido, el cliente recibe el número de puerto del procedimiento del servidor portmap (IM) y se pueden realizar más solicitudes directamente a este puerto.

Manejo de situaciones especiales (excepción)

Manejar excepciones al llamar a procedimientos locales no es particularmente problemático. UNIX proporciona procesamiento para errores de proceso como división por cero, acceso a un área de memoria no válida, etc. En el caso de una llamada a un procedimiento remoto, la probabilidad de que se produzcan situaciones de error aumenta. Además de los errores del servidor y del código auxiliar, se agregan errores asociados, por ejemplo, con la recepción de un mensaje de red erróneo.

Por ejemplo, cuando se utiliza UDP como protocolo de transporte, los mensajes se retransmiten después de un tiempo de espera determinado. Se devuelve un error al cliente si, después de un cierto número de intentos, no se ha recibido respuesta del servidor. En el caso de que se utilice el protocolo TCP, se devuelve un error al cliente si el servidor ha cerrado la conexión TCP.

Semántica de llamadas

Llamar inequívocamente a un procedimiento local conduce a su ejecución, tras lo cual el control vuelve al programa principal. La situación es diferente cuando se llama a un procedimiento remoto. Es imposible determinar cuándo exactamente se realizará el procedimiento, si se realizará y, de ser así, ¿cuántas veces? Por ejemplo, si el sistema remoto recibe la solicitud después de que el programa del servidor haya fallado, el procedimiento no se ejecutará en absoluto. Si el cliente, al no recibir una respuesta después de un cierto período de tiempo (tiempo de espera), reenvía la solicitud, entonces puede surgir una situación en la que la respuesta ya se transmite a través de la red y la solicitud repetida se acepta nuevamente para su procesamiento por parte del control remoto. procedimiento. En este caso, el procedimiento se realizará varias veces.

Así, la ejecución de un procedimiento remoto se puede caracterizar por la siguiente semántica:

  • Una vez y sólo una vez. Este comportamiento (en algunos casos el más deseable) es difícil de exigir debido a posibles fallas del servidor.
  • Tiempos máximos. Esto significa que el procedimiento no se realizó en absoluto o se realizó solo una vez. Se puede hacer una afirmación similar al recibir un error en lugar de una respuesta normal.
  • Al menos una vez. El procedimiento probablemente se realizó una vez, pero es posible más. Para funcionar normalmente en tal situación, el procedimiento remoto debe tener la propiedad de idempotencia (del inglés idemponent). Esta propiedad la posee un procedimiento cuya ejecución repetida no provoca cambios acumulativos. Por ejemplo, leer un archivo es idempotente, pero agregar texto a un archivo no lo es.

Presentación de datos

Cuando el cliente y el servidor se ejecutan en el mismo sistema en la misma computadora, no hay problemas de incompatibilidad de datos. Tanto para el cliente como para el servidor, los datos en formato binario se representan de la misma manera. En el caso de una llamada remota, el asunto se complica por el hecho de que el cliente y el servidor pueden estar ejecutándose en sistemas con diferentes arquitecturas, con diferentes representaciones de datos (por ejemplo, representación de punto flotante, orden de bytes, etc.)

La mayoría de las implementaciones del sistema RPC definen alguna representación de datos estándar a la que se deben convertir todos los valores pasados ​​en solicitudes y respuestas.

Por ejemplo, el formato para presentar datos en RPC de Sun Microsystems es el siguiente:

  1. Orden de bytes: más significativo: último
  2. Representación de coma flotante - IEEE
  3. Representación de caracteres - ASCII

Neto

En términos de funcionalidad, el sistema RPC ocupa un lugar intermedio entre la capa de aplicación y la capa de transporte. Según el modelo OSI, esta disposición corresponde a las capas de presentación y sesión. Por tanto, RPC es teóricamente independiente de la implementación de la red, en particular, de los protocolos de red de la capa de transporte.

Las implementaciones de software del sistema, por regla general, admiten uno o dos protocolos. Por ejemplo, el sistema RPC desarrollado por Sun Microsystems admite la transmisión de mensajes mediante los protocolos TCP y UDP. La elección de un protocolo u otro depende de los requisitos de la aplicación. La elección del protocolo UDP se justifica para aplicaciones que tengan las siguientes características:

  • Los procedimientos llamados son idempotentes.
  • El tamaño de los argumentos transmitidos y el resultado devuelto es menor que el tamaño del paquete UDP: 8 KB.
  • El servidor permite trabajar con varios cientos de clientes. Dado que al trabajar con protocolos TCP, el servidor se ve obligado a mantener una conexión con cada uno de los clientes activos, esto consume una parte importante de sus recursos. El protocolo UDP consume menos recursos a este respecto

Por otro lado, TCP proporciona un funcionamiento eficiente de aplicaciones con las siguientes características:

  • La aplicación requiere un protocolo de transferencia confiable.
  • Los procedimientos llamados no son idénticos
  • El tamaño de los argumentos o resultado devuelto supera los 8 KB.

La elección del protocolo suele dejarse en manos del cliente y el sistema organiza la generación y transmisión de mensajes de diferentes formas. Por tanto, cuando se utiliza el protocolo TCP, para el cual los datos transmitidos son un flujo de bytes, es necesario separar los mensajes entre sí. Para ello se utiliza, por ejemplo, el protocolo de marcado de registros descrito en RFC1057 "RPC: Remote Procedimiento Call Protocol especificación versión 2", en el que se coloca un entero de 32 bits al inicio de cada mensaje, definiendo el tamaño del mensaje. en bytes.

La situación es diferente con la semántica de la llamada. Por ejemplo, si RPC se realiza utilizando un protocolo de transporte no confiable (UDP), el sistema retransmite el mensaje en intervalos cortos (tiempos de espera). Si la aplicación cliente no recibe una respuesta, entonces es seguro decir que el procedimiento se ha ejecutado cero o más veces. Si se recibe respuesta, la solicitud puede concluir que el procedimiento se ejecutó al menos una vez. Cuando se utiliza un protocolo de transporte confiable (TCP), si se recibe una respuesta, se puede decir que el procedimiento se realizó una vez. Si no se recibe respuesta, es imposible decir definitivamente que el trámite no se completó3.

¿Cómo funciona?

Esencialmente, el sistema RPC en sí está integrado en el programa cliente y en el programa servidor. Es bueno que al desarrollar aplicaciones distribuidas no sea necesario profundizar en los detalles del protocolo RPC o el procesamiento de mensajes del programa. El sistema supone la existencia de un entorno de desarrollo adecuado, lo que simplifica enormemente la vida de los creadores de software de aplicaciones. Uno de los puntos clave en RPC es que el desarrollo de una aplicación distribuida comienza con la definición de una interfaz de objeto: una descripción formal de las funciones del servidor, escrita en un lenguaje especial. En función de esta interfaz, los resguardos de cliente y servidor se generan automáticamente. Lo único que debe hacer después de esto es escribir el código real para el procedimiento.

Como ejemplo, considere RPC de Sun Microsystems. El sistema consta de tres partes principales:

  • rpcgen(1) es un compilador RPC que, basándose en la descripción de la interfaz del procedimiento remoto, genera stubs de cliente y servidor en forma de programas C.
  • La biblioteca XDR (eXternal Data Representation), que contiene funciones para convertir varios tipos de datos en un formato independiente de la máquina que permite el intercambio de información entre sistemas heterogéneos.
  • Una biblioteca de módulos que aseguran el funcionamiento del sistema en su conjunto.

Veamos un ejemplo de una aplicación de registro de eventos distribuida simple. Cuando se inicia el cliente, llama a un procedimiento remoto para escribir un mensaje en el archivo de registro de la computadora remota.

Para hacer esto, deberá crear al menos tres archivos: la especificación de las interfaces de los procedimientos remotos log.x (en el lenguaje de descripción de la interfaz), el texto real de los procedimientos remotos log.c y el texto del archivo principal. programa cliente main () - client.c (en lenguaje C).

El compilador rpcgen(l) crea tres archivos basados ​​en la especificación log.x: el texto de los códigos auxiliares del cliente y del servidor en C (log clnt.c y log svc.c) y el archivo de descripción log.h, utilizado por ambos códigos auxiliares. .

Entonces, veamos los códigos fuente de los programas.

Este archivo especifica los parámetros de registro del procedimiento remoto (números de programa, versión y procedimiento), y también define la interfaz de llamada: argumentos de entrada y valores de retorno. Por lo tanto, se define un procedimiento RLOG que toma una cadena como argumento (que se escribirá en el registro) y el valor de retorno indica de manera estándar el éxito o el fracaso de la operación ordenada.


programa LOG_PROG( versión LOG_VER( En t RLOG(cadena) = 1; ) = 1; ) = 0x31234567;

El compilador rpcgen(l) crea un archivo de encabezado log.h, donde, en particular, se definen los procedimientos:


Miremos este archivo detenidamente. El compilador traduce el nombre RLOG definido en el archivo de descripción de la interfaz a rlog_1, reemplazando los caracteres mayúsculas por minúsculas y agregando el número de versión del programa con un guión bajo. El tipo de devolución ha cambiado de int a int*. Esta es la regla: RPC le permite transmitir y recibir solo las direcciones de los parámetros declarados al describir la interfaz. La misma regla se aplica a la cadena pasada como argumento. Aunque no aparece en print.h, la función rlog_l() en realidad pasa la dirección de la cadena como argumento.

Además del archivo de encabezado, el compilador rpcgen(l) produce módulos de código auxiliar de cliente y de servidor. Básicamente, el texto de estos archivos contiene todo el código para la llamada remota.

El stub del servidor es el programa principal que maneja todas las interacciones de la red con el cliente (más precisamente, con su stub). Para realizar la operación, el stub del servidor realiza una llamada a una función local, cuyo texto debe escribirse:


El código auxiliar del cliente acepta el argumento pasado al procedimiento remoto, realiza las conversiones necesarias, emite una solicitud al servidor portmap(1M), se comunica con el servidor del procedimiento remoto y finalmente pasa el valor de retorno al cliente. Para el cliente, una llamada a un procedimiento remoto se reduce a una llamada a un código auxiliar y no se diferencia de una llamada local normal.

cliente.c


#incluir #incluir"log.h" principal(En t argc carbonizarse*argv) ( CLIENTE *cl; carbonizarse*servidor, *mystring, *clnttime; tiempo_t bintiempo; En t*resultado; si(argc != 2) ( fprintf(stderr, "Formato de llamada: %s Dirección_host\n", argv ); salir (1); ) servidor = argv ; /*Obtener el descriptor del cliente. Si no lo consigue, le informaremos que es imposible establecer conexión con el servidor*/ si((c1 = clnt_create (servidor, LOG_PROG, LOG_VER, "udp")) == NULL) ( clnt_pcreateerror (servidor); salir (2); ) /*Asigna un buffer para la línea*/ micadena = ( carbonizarse*)malloc(100); /*Determinar la hora del evento*/ bintime = tiempo ((time_t *) NULL); clnttime = ctime(&bintime); sprintf (mystring, "%s - Cliente iniciado", clnttime); /*Enviar un mensaje para el registro: la hora en que el cliente comenzó a funcionar. Si no tiene éxito, informaremos un error*/ si((resultado = rlog_l(&mystring, cl)) == NULO) ( fprintf(stderr, "error2\n"); clnt_perror(cl, servidor); exit(3); ) /*En caso de falla en la computadora remota, reportaremos un error*/ si(*resultado!=0) fprintf(stderr, "Error al escribir en el registro\n"); /*0libera el mango*/ cint destruir(cl); salir(0); )

El código auxiliar del cliente log_clnt.c se compila con el módulo client.c para producir un programa cliente ejecutable.


Ahora, en algún host server.nowhere.ru, debe iniciar un proceso de servidor:


$ registrador

Luego, cuando ejecute el cliente rlog en otra máquina, el servidor agregará la entrada correspondiente al archivo de registro.

El diagrama de funcionamiento del RPC en este caso se muestra en la Fig. 1. Los módulos interactúan de la siguiente manera:

  1. Cuando se inicia el proceso del servidor, crea un socket UDP y vincula cualquier puerto local a ese socket. A continuación, el servidor llama a la función de biblioteca svc_register(3N) para registrar números y versiones de programas. Para hacer esto, la función llama al proceso portmap(IM) y pasa los valores requeridos. El servidor portmap(IM) generalmente se inicia cuando el sistema se inicializa y se vincula a algún puerto conocido. Ahora portmap(3N) conoce el número de puerto de nuestro programa y versión. El servidor está esperando recibir la solicitud. Tenga en cuenta que todas las acciones descritas las realiza un código auxiliar de servidor creado por el compilador rpcgen(IM).
  2. Cuando se ejecuta rlog, lo primero que hace es llamar a la función de biblioteca clnt_create(3N), proporcionándole la dirección del sistema remoto, los números de programa y versión, y el protocolo de transporte. La función envía una solicitud al servidor de mapa de puertos (IM) del sistema remoto server.nowhere.m y obtiene el número de puerto remoto para el servidor de registro.
  3. El cliente llama al procedimiento rlog_1() definido en el código auxiliar del cliente y transfiere el control al código auxiliar. Esto, a su vez, genera una solicitud (convirtiendo los argumentos al formato XDR) en forma de paquete UDP y la envía al puerto remoto recibido del servidor de mapa de puertos (IM). Luego espera una respuesta durante algún tiempo y, si no la recibe, reenvía la solicitud. En circunstancias favorables, la solicitud es aceptada por el servidor registrador (módulo de código auxiliar del servidor). El código auxiliar determina qué función se llamó (por número de procedimiento) y llama a la función rlog_1() del módulo log.c. Después de que el control regresa al stub, este último convierte el valor devuelto por la función rlog_1() al formato XDR y genera una respuesta también en forma de paquete UDP. Al recibir la respuesta, el código auxiliar del cliente extrae el valor devuelto, lo transforma y lo devuelve al programa principal del cliente.

La idea de una llamada a procedimiento remoto (RPC) es ampliar el mecanismo bien conocido y comprendido para transferir control y datos dentro de un programa que se ejecuta en una máquina para transferir control y datos a través de una red. Es decir, la aplicación cliente accede a los procedimientos almacenados en el servidor. Las herramientas de llamada a procedimientos remotos están diseñadas para facilitar la organización de la informática distribuida. La mayor eficiencia del uso de RPC se logra en aquellas aplicaciones en las que existe comunicación interactiva entre componentes remotos con tiempos de respuesta rápidos y una cantidad relativamente pequeña de datos transferidos. Estas aplicaciones se denominan orientadas a RPC.

Los rasgos característicos de RPC son:

Asimetría, es decir, una de las partes que interactúan es el iniciador;

Sincronicidad, es decir, la ejecución del procedimiento que llama se suspende desde el momento en que se emite la solicitud y se reanuda solo después de que regresa el procedimiento llamado.

Existen varias implementaciones de procedimientos de llamadas remotas en diferentes sistemas operativos. El sistema operativo UNIX utiliza un procedimiento del mismo nombre (Llamada a procedimiento remoto - RPC). Este procedimiento se implementa en el núcleo del sistema. Su implementación está garantizada por el protocolo RPC. En los sistemas operativos Windows, la llamada a procedimientos remotos comenzó a desarrollarse sobre la base de mecanismos OLE, que gradualmente se convirtieron en la tecnología DCOM (Modelo de objetos componentes distribuidos). Esta tecnología le permite crear entornos informáticos de red distribuidos bastante potentes. La tecnología utiliza protocolos propietarios de Microsoft.

Cómo funciona RPC

Antes de la llamada directa, se deben crear estructuras especiales (procedimientos, archivos) en el lado del cliente y del servidor; estos son los llamados stub del cliente y esqueleto del servidor, que son necesarios para el correcto funcionamiento de RPC. La mayoría de las veces, se generan automáticamente mediante utilidades especiales utilizando el código principal del programa.

Cuando se llama a un procedimiento remoto en un sistema distribuido, ocurren las siguientes acciones:

1. El procedimiento del cliente llama a stub como un procedimiento normal. Parámetros de paquetes de resguardos (serialización).

2. Stub accede al kernel del sistema operativo.

3. El kernel envía un mensaje a la máquina remota (el kernel de la PC remota).

4. Transferir el mensaje recibido al esqueleto del proceso del servidor.

5. Descomprimir parámetros (descomprimir). Llame al trámite requerido.

6. El procedimiento se está ejecutando en el servidor. Devuelve los resultados al esqueleto.

7. El esqueleto contiene el resultado.

8. Transfiera el resultado al kernel.

9. El núcleo del servidor pasa el mensaje a través de la red al núcleo del cliente.

10. El núcleo del cliente accede al código auxiliar. Stub descomprime el resultado.

11. Transferencia del stub al proceso del cliente.

Servicio de llamada a procedimiento remoto (RPC) en el sistema operativo Windows

Para comprender la importancia del mecanismo de llamada a procedimiento remoto, al menos puede considerar la lista de utilidades y servicios que no funcionan sin RPC en Windows 2000. De hecho, deshabilitar el servicio RPC en el entorno especificado provoca el bloqueo de todo el sistema. Entonces, del servicio de Llamada a Procedimiento Remoto (RPC) depende lo siguiente:

1. Telnet: permite a un usuario remoto iniciar sesión y ejecutar programas de consola mediante la línea de comandos.

2. Windows Installer: instala, desinstala o repara software según las instrucciones de los archivos MSI.

3. Agente de políticas IPSEC: administra la política de seguridad IP y ejecuta ISAKMP/Oakley (IKE) y el controlador de seguridad IP.

4. Cola de impresión: carga archivos en la memoria para su posterior impresión.

5. Almacenamiento seguro: proporciona almacenamiento seguro de datos confidenciales, como claves privadas, para evitar el acceso no autorizado por parte de servicios, procesos o usuarios.

6. Instrumental de administración de Windows: proporciona información sobre la administración del sistema.

7. Cliente de seguimiento de enlaces modificado: envía alertas sobre archivos movidos entre volúmenes NTFS en un dominio de red.

8. Coordinador de transacciones distribuidas: coordina transacciones distribuidas en múltiples bases de datos, colas de mensajes, sistemas de archivos u otros administradores de recursos de transacciones seguras.

9. Enrutamiento y acceso remoto: ofrece servicios de enrutamiento a organizaciones en redes locales y globales.

10. Programador de tareas: le permite ejecutar programas a la hora programada.

11. Conexiones de red: administra objetos en la carpeta "Red y red de acceso remoto", que muestra las propiedades de la red local y las conexiones de acceso remoto.

12. Sistema de eventos COM+: distribución automática de eventos a componentes COM suscritos.

13. Servicio de indexación: indexación para búsqueda rápida.

14. Servicio de mensajería: envía y recibe mensajes enviados por los administradores o el servicio de notificación.

15. Servicio de fax: le ayuda a enviar y recibir mensajes de fax.

16. Almacenamiento extraíble: gestiona bibliotecas, discos y medios extraíbles.

17. Telefonía: brinda soporte para la API de telefonía (TAPI) para programas que administran equipos telefónicos y conexiones de voz IP en esta computadora, así como a través de la LAN, en servidores donde se ejecuta el servicio correspondiente.

Aplicaciones RMI

La invocación de método remoto (RMI) es una implementación de ideas de RPC para el lenguaje de programación Java.

RMI es un producto JavaSoft desarrollado para Java e integrado en JDK 1.1 y superior. RMI implementa un modelo informático distribuido y proporciona un medio de comunicación entre programas Java (máquinas virtuales Java) que se ejecutan en una o más computadoras remotas. RMI permite que las aplicaciones cliente y servidor llamen a métodos de clientes/servidores que se ejecutan en máquinas virtuales Java a través de la red. La principal ventaja de RMI es que proporciona al programador una interfaz programable de nivel superior que permite pasar una referencia a un objeto remoto como argumento o devolverlo como resultado. RMI requiere que se ejecuten programas Java en ambos extremos de la conexión. La conexión de red se logra mediante el protocolo TCP/IP. La arquitectura RMI se muestra en la Fig. "Arquitectura RMI".

Client Stub (un adaptador para el cliente, una determinada entidad en el cliente que proporciona funciones de recepción/transmisión) y Server Skeleton (un adaptador para el servidor, una determinada entidad en el servidor que procesa llamadas remotas) se derivan de la interfaz común. , pero difieren en que el Client Stub simplemente se usa para conectarse al Registro RMI y el Server Stub se usa para comunicarse directamente con las funciones del servidor.

RMI es en realidad un nuevo tipo de intermediario de solicitud de objetos construido sobre el modelo de objetos Java. Al igual que ORB, RMI presenta cinco puntos clave:

1. Le permite mover código además de datos.

2. Garantiza prácticamente la seguridad de ejecución del código cargado.

3. Le permite pasar objetos por valor.

4. Utiliza Java como lenguaje de definición de interfaz y lenguaje de implementación.

5. Utiliza un esquema de nomenclatura basado en el Localizador uniforme de recursos (URL).

Esto convierte los objetos en formato serial, en un flujo de bytes transmitidos como parámetro en un mensaje utilizando el protocolo TCP/IP.

Las interfaces RMI se pueden dividir en 4 categorías:

RMI Core: define las interfaces necesarias para realizar llamadas a métodos remotos;

Servicio de nombres RMI: define interfaces y clases que le permiten obtener referencias a objetos del servidor por nombre;

Seguridad RMI: define un nuevo administrador de seguridad RMI y interfaces de cargador de clases (RMI extiende el mecanismo de carga de clases Java bajo demanda a la carga de códigos auxiliares);

Marshalización (empaquetar una solicitud, incluidos los parámetros, el valor de retorno y la solicitud en sí, en un formato estándar adecuado para la transmisión a través de una red): RMI define interfaces de bajo nivel para ordenar objetos remotos, que se utilizan para escribir objetos Java en una secuencia y para leer un objeto de una secuencia.

JavaSoft y OMG están trabajando para acercar los modelos de objetos RMI y CORBA. Esta convergencia se produce en dos áreas:

RMI vía IIOP. JavaSoft está desarrollando una versión de RMI que se ejecuta sobre el transporte IIOP. IIOP proporciona los siguientes beneficios a RMI:

1. Soporte integrado para distribución de transacciones.

2. Soporte de firewall basado en ORB usando proxy IIOP (sin túnel HTTP).

3. Interacción con objetos escritos en otros lenguajes a través de un subconjunto de RMI/IDL.

4. Estándar abierto para objetos distribuidos.

RMI/IDL. El estándar CORBA Java en IDL es un estándar de convergencia CORBA/RMI. Permite a los programadores de Java definir interfaces CORBA utilizando la semántica Java RMI en lugar de CORBA IDL. El compilador utiliza esta semántica para generar automáticamente CORBA IDL, resguardos y esqueletos. El subconjunto RMI/IDL permite que clientes CORBA multilingües llamen a programas RMI utilizando IIOP; también permite que los programas RMI llamen a objetos CORBA escritos en otros lenguajes.

RMI sobre IIOP parece ser una buena solución para un sistema CORBA/Java porque combina dos tecnologías poderosas. La principal ventaja de RMI es que le permite crear rápida y fácilmente un pequeño sistema distribuido en un entorno puramente Java. La principal desventaja de RMI es que no se puede integrar con aplicaciones existentes.

Comparación de programas Java distribuidos y no distribuidos

Los desarrolladores de RMI pretendían que el uso de objetos Java distribuidos fuera lo mismo que el uso de objetos locales. La siguiente tabla enumera algunas diferencias importantes.

Interfaces en RMI

La arquitectura RMI se basa en un principio importante: definir el comportamiento e implementar ese comportamiento se consideran conceptos diferentes. RMI permite separar y ejecutar en diferentes JVM el código que define el comportamiento y el código que implementa el comportamiento.

Esto cumple con los requisitos de los sistemas distribuidos en los que los clientes conocen las definiciones de servicios y los servidores proporcionan esos servicios. Específicamente, en RMI, la definición de un servicio remoto se codifica mediante una interfaz Java. La implementación del servicio remoto está codificada en una clase. Entonces, la clave para comprender RMI es recordar que las interfaces definen el comportamiento y las clases definen la implementación.

Recuerde que las interfaces Java no contienen código ejecutable. RMI admite dos clases que implementan la misma interfaz. La primera clase es la implementación del comportamiento y se ejecuta en el servidor. La segunda clase funciona como una interfaz intermedia para el servicio remoto y se ejecuta en la máquina cliente.

El programa cliente llama a los métodos del objeto proxy, RMI pasa la solicitud a la JVM remota y la reenvía a la implementación del objeto. Cualquier valor devuelto por la implementación se devuelve al objeto proxy y luego al programa cliente.

Capas de arquitectura RMI

Una implementación RMI consta esencialmente de tres capas abstractas. El primero es el nivel del trozo y del esqueleto, ubicado directamente frente al desarrollador. Esta capa intercepta las llamadas a métodos realizadas por el cliente utilizando una variable de referencia de interfaz y las reenvía al servicio RMI remoto.

El siguiente nivel es el nivel de enlace remoto. Esta capa comprende cómo interpretar y gestionar referencias a objetos de servicios remotos. En JDK 1.1, esta capa conecta a los clientes con objetos de servicio remotos que se ejecutan en el servidor. Esta conexión es una conexión uno a uno (conexión unidireccional). En el SDK de Java 2, esta capa se amplió para admitir la activación de objetos remotos pasivos mediante la tecnología de activación remota de objetos.

La capa de transporte se basa en conexiones TCP/IP entre máquinas en red. Proporciona conectividad básica y algunas estrategias antimanipulación. Con una arquitectura en capas, cada capa se puede cambiar o reemplazar sin afectar al resto del sistema. Por ejemplo, la capa de transporte puede ser reemplazada por el protocolo UDP/IP sin cambiar las otras capas.

Buscar objetos eliminados

Al considerar la arquitectura RMI, surge la pregunta: "¿Cómo encuentra el cliente el servicio RMI remoto?" Los clientes encuentran servicios remotos utilizando un servicio de nombres o directorio. ¿Cómo puede un cliente encontrar un servicio utilizando un servicio? Pero esto es cierto. El servicio de nombre o directorio se ejecuta en un host conocido y tiene un número de puerto conocido (conocido significa que todos en la organización lo saben).

RMI puede utilizar muchos servicios de directorio diferentes, incluida Java Naming and Directory Interface (JNDI). El propio RMI incluye un servicio sencillo llamado registro RMI, rmiregistry. El registro RMI se ejecuta en cada máquina que aloja objetos de servicio remoto y acepta solicitudes de servicio, utilizando de forma predeterminada el puerto 1099. En el host, el programa del servidor crea un servicio remoto creando primero un objeto local que implementa ese servicio. Luego exporta este objeto a RMI. Una vez exportado el objeto, RMI crea un servicio de escucha que espera la conexión del cliente y la solicitud de servicio. Después de la exportación, el servidor registra el objeto en el registro RMI utilizando el nombre público.

En el lado del cliente, se accede al registro RMI a través de la clase de denominación estática. Proporciona un método de búsqueda () que el cliente utiliza para consultar el registro. El método lookup() acepta una URL que apunta al nombre de host y al nombre del servicio requerido. El método devuelve una referencia remota al objeto de servicio. La URL toma la siguiente forma:

rmi:// [:] /
donde nombre_host es un nombre reconocido en una red de área local (LAN) o un nombre DNS en Internet. Solo necesita especificar nombre_servicio_puerto si el servicio de nombres se ejecuta en un puerto distinto al 1099 predeterminado.

Usando RMI

Un sistema RMI en funcionamiento consta de varias partes: definir interfaces para servicios remotos, implementar servicios remotos, archivos stub y esqueleto, un servidor que expone servicios remotos, un servicio de nombres RMI que permite a los clientes encontrar servicios remotos, un proveedor de archivos de clase (HTTP o Servidor FTP) ), un programa cliente que necesita servicios remotos.

Suponiendo que el sistema RMI ya ha sido diseñado, se deben seguir los siguientes pasos para crearlo:

1. Escriba y compile código Java para las interfaces.

2. Escribir y compilar código Java para clases de implementación.

3. Cree archivos de clases stub y esqueleto a partir de las clases de implementación.

4. Escriba código Java para el programa host para mantenimiento remoto.

5. Desarrollar código Java para el programa cliente RMI.

6. Instale e inicie el sistema RMI.

Ejemplo RMI: aplicaciones

El primer paso es escribir y compilar el código Java para las interfaces de servicio. La interfaz de la Calculadora define todas las capacidades remotas que ofrece el servicio:

La calculadora de interfaz pública extiende java.rmi.Remote (
public long add (long a, long b) lanza java.rmi.RemoteException;
public long sub(long a, long b) lanza java.rmi.RemoteException;
public long mul (long a, long b) lanza java.rmi.RemoteException;
public long div (long a, long b) lanza java.rmi.RemoteException;
}

Tenga en cuenta que esta interfaz amplía la interfaz remota y la firma de cada método especifica que puede generar un objeto RemoteException. En general, un objeto se llama remoto si implementa la interfaz Remota. "Implementos" en el sentido del encabezado (la interfaz pública Calculadora extiende java.rmi.Remote), no hay métodos en esta interfaz. Esta es una marca. Ahora necesitas escribir una implementación del servicio remoto. A continuación se muestra la clase CalculatorImpl:

La clase pública CalculatorImpl extiende java.rmi.server.UnicastRemoteObject
implementa Calculadora (
// Las implementaciones deben tener un constructor explícito para poder declarar
// excepción Excepción Remota
Calculadora públicaImpl()
lanza java.rmi.RemoteException (
súper();
}
public long add (long a, long b) lanza java.rmi.RemoteException (
devolver a + b;
}
public long sub(long a, long b) lanza java.rmi.RemoteException (
devolver a-b;
}
public long mul(long a, long b) lanza java.rmi.RemoteException (
devolver a * b;
}
public long div (long a, long b) lanza java.rmi.RemoteException (
devolver a/b;
}
}

La clase de implementación utiliza Unicast RemoteObject para conectarse al sistema RMI. En este ejemplo, la clase de implementación extiende directamente UnicastRemoteObject. Esto no es un requisito. Una clase que no extiende UnicastRemoteObject puede usar su método exportObject() para adjuntarse a RMI. Si una clase extiende UnicastRemoteObject, debe proporcionar un constructor que declare que puede generar un objeto RemoteException. Si este constructor llama al método super(), invoca código en UnicastRemoteObject que realiza la conexión RMI y la inicialización del objeto remoto.

Los servicios RMI remotos deben colocarse en el proceso del servidor. La clase CalculatorServer es un servidor muy simple que proporciona elementos simples para alojar.

importar java.rmi.Naming;

Servidor de Calculadora de clase pública (
Servidor de Calculadora pública() (
intentar (
Calculadora c = nueva CalculadoraImpl();
Nombrar.rebind("
rmi://localhost:1099/
CalculadoraServicio", c);
) captura (Excepción e) (
System.out.println("Problema: " + e);
}
}
nuevo Servidor de Calculadora();
}
}

El código fuente del cliente, por ejemplo, podría ser el siguiente:

importar java.rmi.Naming;
importar java.rmi.RemoteException;
importar java.net.MalformedURLException;
importar java.rmi.NotBoundException;
Cliente de Calculadora de clase pública (
principal público estático vacío (argumentos de cadena) (
intentar (
Calculadora c = (Calculadora)
Nombrar.búsqueda(
"rmi://host remoto
/ServicioCalculadora");
System.out.println(c.sub(4, 3));
System.out.println(c.add(4, 5));
System.out.println(c.mul(3, 6));
System.out.println(c.div(9, 3));
}
captura (MalformedURLException murle) (
Sistema.out.println();
System.out.println(
"Excepción de URL mal formada");
System.out.println(murle);
}
captura (RemoteException re) (
Sistema.out.println();
System.out.println(
"Excepción remota");
System.out.println(re);
}
captura (NotBoundException nbe) (
Sistema.out.println();
System.out.println(
"NotBoundException");
System.out.println(nbe);
}
atrapar(
java.lang.ArithmeticException
ae) (
Sistema.out.println();
System.out.println(
"java.lang.ArithmeticException");
System.out.println(ae);
}
}
}

Ahora puedes iniciar el sistema. Esto se puede hacer (después de recibir los archivos de clase apropiados y colocarlos en la misma PC o en diferentes) de esta manera:

1. Inicie el registro RMI (“rmiregistry”).

2. Inicie el servidor ("java CalculatorServer").

3. Inicie el cliente ("java CalculatorClient").

Si todo va bien, verás la siguiente información:

1
9
18
3

Eso es todo: un sistema RMI que funciona está listo. Incluso si ejecuta tres consolas en la misma computadora, RMI utiliza la pila de protocolos TCP/IP de su red para comunicarse entre las tres JVM independientes. Este es un sistema RMI completamente completo.

Distribución de clases RMI

Para ejecutar una aplicación RMI, los archivos de clase de soporte deben ubicarse en lugares donde el servidor y los clientes puedan encontrarlos.

Las siguientes clases deben estar disponibles para el servidor (para el cargador de clases):

Implementaciones de servicios remotos

Esqueletos para clases de implementación (solo para servidores basados ​​en JDK 1.1)

Stubs para clases de implementación

Todas las demás clases de servidores

Las siguientes clases deben estar disponibles para el cliente (para el cargador de clases):

Definiciones de interfaz de servicio remoto

Talones para clases que implementan un servicio remoto

Clases de servidor para objetos utilizados por el cliente (como el valor de retorno)

Todas las demás clases de clientes

Si sabe qué archivos deben ubicarse en diferentes nodos de la red, entonces es fácil ponerlos a disposición de cada cargador de clases JVM.

Recolección de basura distribuida

Uno de los beneficios de programar para la plataforma Java es que no tienes que preocuparte por la asignación de memoria. La JVM tiene un recolector de basura automático que libera la memoria ocupada por cualquier objeto que ya no esté en uso por el programa en ejecución. Uno de los requisitos para el desarrollo de RMI fue su perfecta integración en el lenguaje de programación Java, incluida la recolección de basura. Desarrollar un recolector de basura eficiente para una sola máquina es una tarea difícil; Desarrollar un recolector de basura distribuido es una tarea muy difícil. El sistema RMI proporciona un algoritmo de recolección de basura distribuida con recuento de referencias basado en los objetos de red utilizados en Modula-3. Durante el funcionamiento, este sistema monitorea qué clientes han solicitado acceso a objetos remotos que se ejecutan en el servidor. Cuando aparece un enlace, el servidor marca el objeto como "sucio" y cuando el cliente elimina el enlace, el objeto se marca como "limpio".

La interfaz con el DGC (recolector de basura distribuido) está oculta en el nivel de código auxiliar y esqueleto. Sin embargo, un objeto remoto puede implementar la interfaz java.rmi.server.Unreferenced y recibir una notificación a través del método sin referencia cuando ya no haya clientes que tengan una referencia activa. Además del mecanismo de conteo de enlaces, un enlace activo en el cliente tiene un período de arrendamiento con un tiempo específico. Si el cliente no renueva la conexión con el objeto remoto antes de que expire el contrato de arrendamiento, el vínculo se considera inactivo y el objeto remoto puede ser objeto de recolección de basura. El tiempo de concesión está controlado por la propiedad del sistema java.rmi.dgc.leaseValue. Su valor se especifica en milisegundos y el valor predeterminado es 10 minutos. Debido a esta semántica de recolección de basura, el cliente debe estar preparado para tratar con objetos que pueden "desaparecer".

Conclusión

La invocación de método remoto (RMI), introducida por primera vez en JDK 1.1, llevó la programación de redes a un nivel superior. Aunque RMI es relativamente fácil de usar y no está exento de deficiencias, es una tecnología increíblemente poderosa y expone al programador Java promedio a un paradigma completamente nuevo: el mundo de la computación de objetos distribuidos.