# Petición-respuesta

En informática, el esquema, protocolo o modelo de petición-respuesta es una de las principales formas en que las computadoras se comunican entre sí en una red. Consiste en que una computadora envía una petición a otra para solicitar un recurso y la segunda recibe esa petición, la procesa y devuelve un mensaje de respuesta. Este modelo es muy representativo en el paso de mensajes y en el intercambio bidireccional de mensajes tal como se puede observar en la metodología cliente-servidor. En particular, dichos protocolos proporcionan soporte de nivel relativamente bajo para solicitar la ejecución de una operación remota, y también proporcionan soporte directo para RPC (Remote procedure call) y RMI (Remote method invocation).
Esta forma de comunicación está diseñada para apoyar los roles y los intercambios de mensajes en interacciones típicas cliente-servidor.
Normalmente, la comunicación de petición-respuesta es síncrona ya que el proceso cliente se bloquea hasta la llegada de la respuesta del servidor, pudiendo interpretarse como una forma de reconocimiento del cliente por parte del servidor. Aunque en ocasiones, cuando los clientes pueden permitirse el lujo de recuperar la respuesta más tarde, la comunicación puede que sea asíncrona.

## Primitivas

El protocolo se basa en un trío de primitivas de comunicación. En el protocolo habrá el mismo número de peticiones que respuestas y puede estar diseñado para proporcionar ciertas garantías de entrega, como si utilizamos datagramas UDP, en cuyo caso el protocolo debe garantizar las entregas mediante acuses de recibo por parte del servidor hacia el cliente.
* doOperation(s,args): los clientes utilizan este método para invocar operaciones remotas. Sus argumentos especifican el servidor remoto (s) y que operación invocar junto con información adicionar requerida por la operación (args). Este método envía un mensaje de solicitud al servidor y después invoca receive para obtener el mensaje de respuesta del cual extrae el resultado y lo devuelve al invocador del método. Este invocador permanece bloqueado hasta que el servidor realiza la operación solicitada y devuelve un mensaje de respuesta al cliente.
* getRequest: lo utiliza el servidor para obtener las peticiones de servicio.
* sendReply(r,c): cuando el servidor ha realizado la operación que se le ha solicitado usa sendReply para enviar el mensaje de respuestas al cliente. Cuando el cliente recibe el mensaje de respuesta se desbloquea y su ejecución puede continuar. Respecto a sus parámetros, el primer campo indica si el mensaje es una solicitud o una respuesta. El segundo campo contiene un identificador de un mensaje.

## Identificadores de mensajes

Cualquier esquema que implique la gestión de mensajes para realizar acciones como la entrega segura de mensajes o la solicitud de respuesta requerirá que cada mensaje tenga un identificador de mensaje único mediante el cual pueda ser referenciado.
En este caso, los identificadores de mensajes cuentan con dos partes, una que hace que el identificador sea único para el remitente, y la segundo parte que hace que ese mensaje sea único en el sistema distribuido.
Una operación en el cliente genera el identificador para cada mensaje de solicitud y el servidor copia estos identificadores en los mensajes de respuesta correspondientes para que doOperation pueda verificar que una respuesta es el resultado de una solicitud actual y uno una anterior que esté retrasada.

## Modelo de fallo

* Por omisión: el servidor no responde o el mensaje se pierde. Para solucionar esto, doOperation puede implementar un timeout en su espera por el mensaje de respuesta. Hay varias opciones sobre lo que puede hacer una vez finalice el tiempo de espera, la más simple es finalizar con un mensaje de que la operación ha fallado. Pero esto no es lo que sucede habitualmente. Lo normal es que para compensar la posibilidad de que haya mensajes perdidos, doOperation envíe el mensaje de solicitud repetidamente hasta que recibe una respuesta o bien determina que el servidor está caído porque han pasado un determinado número de intentos. Finalmente, cuando regresa doOperation, indicará al cliente, a través de una excepción, que no se ha recibido ningún resultado.
* Bizantino: el servidor recibe peticiones duplicadas. Hay ocasiones en los que el mensaje de solicitud es retrasmitido y el servidor puede recibirlo más de una vez, como por ejemplo si tarda más en ejecutar la operación que el tiempo de espera del cliente, en cuyo caso este volverá a enviársela. Esto puede llevar a que se realicen determinadas operaciones más de una vez por error. Para evitar esto, el protocolo está diseñado para reconocer mensajes sucesivos del mismo cliente y con el mismo identificador y poder filtrar los duplicados. Si ya la ha realizado y la operación es idempotente, la realiza de nuevo; si no, puede implementar un histórico con los resultados de las operaciones realizadas.

## Variaciones

* Request (R): el cliente envía un único mensaje de solicitud al servidor. Este protocolo puede ser utilizado cuando no hay ningún valor que devolver de la operación remota y el cliente no requiere de confirmación de que la operación se haya realizado.
* Request-Reply (RR): este es el protocolo básico, el cual es útil para la mayoría de los intercambios cliente-servidor. No se requieren mensajes ack, ya que el mensaje de respuesta de un servidor se considera como un reconocimiento de cliente. Del mismo modo, una llamada posterior de un cliente puede considerarse como un acuse de recibo del mensaje de respuesta de un servidor.
* Request-Reply-Acknowledge (RRA): el protocolo se basa en el intercambio de tres tipos de mensaje: petición, respuesta y confirmación de respuesta. El mensaje de confirmación de respuesta contiene un identificador del mensaje de respuesta para poder ser reconocido. Esto permitirá al servidor descartar algunos mensajes. La llegada del mensaje de confirmación será interpretado como un acuse de recibo de todos los mensajes de respuesta con un identificador de solicitud más bajo que el de este. Aunque el intercambio involucra un mensaje adicional, no es necesario bloquear al cliente ya que el reconocimiento puede ser transmitido después de que se haya dado la respuesta al cliente. La principal desventaja de este modo es que utiliza más recursos.

## Ejemplos

Un buen ejemplo de protocolo de petición-respuesta es HTTP (Hypertext Transfer Protocol) el cual es un protocolo que permite hacer peticiones a servidores web (páginas HTML, Applets, Servlets...)
Las peticiones especifican una URL que incluye:
* DNS host servidor
* Número de puerto
* Identificador de un recurso
Define una serie de métodos de petición:
* PUT: reemplaza todas las representaciones actuales del recurso de destino con la carga útil de la petición.
* GET: pide el recurso cuya URL se da como argumento. Si es un dato, el servidor lo retorna Si es un programa, el servidor lo ejecuta y devuelve su salida Se puede añadir argumentos a la URL para el programa.
* POST: especifica la URL de un recurso que pueda tratar con los datos suministrados en el cuerpo del mensaje (postear en una lista de correo/modificar un perfil web, añadir entradas a una base de datos, proveer datos a un programa (p.ej un formulario)).
* UPDATE: actualiza un recurso existente.
* DELETE: se utiliza para eliminar un registro existente..