Programación con RPC: Definiendo el servicio

Antes de empezar a escribir alguna linea de código, no importa que tipo de programa sea, siempre tienes que definir para que servirá el programa, es decir, su funcionamiento, que datos procesa y cuales genera a partir de esta; con la programación con RPC no es la excepción. Ya que antes de definir alguna función que deseas ejecutar de forma remota (no siempre es así) primero hay que definir que parámetros recibirá y cuales regresara, así como los tipos de datos que va a necesitar.

Como se mencionó en la entrada anterior, el ejemplo sera un servicio que reciba peticiones llamando a una función y que retorne una estructura de datos al cliente con la información del proceso que realizo la tarea.

Empezamos con el código que rpcgen procesara para generar la interfaz:

/* Define process info struct */
struct process_info {
	string name<>;
	int pid;
	int ppid;
	int uid;
	int gid;
};

program PROCESS {
	version ONE {
		process_info GET_PROCESS_INFO(void) = 1;
	} = 1;
} = 20000000;

En este archivo se define una estructura al muy parecido al estilo C, con algunas excepciones: rpcgen siempre genera un typedef de la estructura, siendo innecesario poner la palabra clave struct antes del nombre, tambien al referirse a una cadena de caracteres se usa la palabra clave string en vez de la conocida char * , este es un punto muy importante ya que el protocolo RPC tiene una manera de trabajar con los tipos primitivos: (int, short, longfloat, double, array, pointer, string, etc); por ultimo, es importante tener en cuenta que no se puede cambiar fácilmente los tipos que se utilizaran en el servicio, ya que se tiene que actualizar todo el código, por eso se debe tener en claro que necesitaras. También existen otros tipos que son mas complejos en definición pero son muy útiles en ciertas circunstancias las cuales se presentan muy comúnmente en la programación normal. Algunos ejemplos son:

/* Ejemplo de diferentes estructuras de datos */
struct otra_estructura {
	int id;
	string nombre<>;
	string direccion<>;
};

struct otra_mas {
	int operacion;
	double dato1;
	double dato2;
	double dato3;
};

Después de definir los tipos utilizados se sigue con la definición del servicio en si. Primero se escribe la palabra clave program que describe el nombre del servicio, el cual es solo una referencia ya que al final se establece un valor numero fijo el cual servirá para reconocer el servicio al cual queremos llamar. Después de definir el nombre y antes de definir un valor ponemos unos corchetes y escribimos la palabra clave version la cual establece al nombre definido un valor que define la versión del servicio que solicitamos, generalmente se empieza por 1 hasta el numero de versiones que haya, algunos servicios como NFS tienen diferentes interfaces de comunicación agrupadas por versiones, esto es para evitar conflictos en caso de añadir una nueva funcionalidad y afectar a los clientes con versiones anteriores, al igual que el anterior entre el nombre y numero de versión, colocamos las funciones que llamaremos desde el cliente hacia el servidor. Estos se definen al estilo C pero con la excepción que también se le establece un valor numérico el cual cumple la función de identificar el procedimiento que estamos llamando. Un ejemplo diferente:

/* Se definirá un servicio con dos versiones diferentes,
 * las cuales proporcionan la misma función pero con diferentes
 * parámetros. */
program NOMBRE_SERVICIO {
	version VERSION_UNO {
		int get_double (int) = 1;
	} = 1; /* verison 1 */
	version VERSION_DOS {
		long get_double (long) = 1;
	} = 2; /* version 2 */
} = 20000001; /* Numero de servicio: puede ser cualquiera,
               * con algunas excepciones */

Regresando al código original, este es solo una interfaz, en si no puede ser compilado como cualquier código fuente en C, sino debe ser procesado por rpcgen para generar el código apropiado, hay que tomar en cuenta que solo generara las bases del servidor y del cliente, pero se debe definir a mano las funciones del servidor, así como las llamadas que hará el cliente y como usara la información que obtendrá. Para generar los archivos se ejecuta el siguiente comando:

$ rpcgen process.x

Siendo process.x el nombre del código RPC que aparece al principio del tutorial. Los archivos resultantes de ello son:

  • process.h: Archivo de cabecera que posee las definiciones y variables utilizadas tanto por el cliente como por el servidor.
  • process_xdr.c: Archivo de código fuente en C que maneja el tipo process_info de forma dinámica para ser manejado por el protocolo RPC.
  • process_svc.c: Archivo de código fuente en C que define la parte principal de servidor RPC, pero no define las funciones que serán llamadas por el cliente.
  • process_clnt.c: Archivo de código fuente en C que se encarga de abstraer la llamada del procedimiento remoto.

En el siguiente post se definirá una versión mínima del servicio process complementando el código faltante.

Anuncios

Reapertura del Blog

Han pasado mas de dos años desde la última publicación en el Blog de DarkMega Zero, por varias razones no se había hecho alguna publicación pero próximamente habrá mas contenido referido a temas como programación y diseño de sistemas, así como temas específicos como videojuegos o aplicaciones personalizables. Espero poder cumplir con mi objetivo esta vez. Si tienen alguna duda o pregunta sobre el funcionamiento de Linux o un caso de programación con gusto los apoyaré.