Programando con RPC: Definiendo el servidor

Esta es la tercera parte de la serie de post sobre la programación con RPC, en este se implementará el funcionamiento del servidor, aunque parezca sencillo, y la verdad lo es, puede ser un poco complicado hacerlo debidamente ya que se debe tomar en cuenta aspectos como: uso adecuado de memoria, manejo de punteros y, en algunos casos, concurrencia. Como se comentaba en el post anterior el objetivo es hacer un servicio que retorne su información como proceso del sistema (nombre, usuario, id de proceso, etc).

Primero, no es obligatorio pero si recomendable, ejecutar el comando rpcgen con el parámetro -Ss:

$ rpcgen -Ss process.x

Esta orden hacé que el generador de código RPC cree una plantilla para empezar a implementar la función que hará el servidor, es decir, el procedimiento que sera llamado cuando sea requerido por el cliente. Algo como esto sera generado:

/*
 * This is sample code generated by rpcgen.
 * These are only templates and you can use them
 * as a guideline for developing your own functions.
 */

#include "process.h"

process_info *
get_process_info_1_svc(void *argp, struct svc_req *rqstp)
{
	static process_info  result;

	/*
	 * insert server code here
	 */

	return &result;
}

La función get_process_info_1_svc() define las acciones que serán tomadas del servidor, argp es el argumento de entrada, siempre en esta implementar de RPC la función toma solo un argumento de entrada por lo cual es necesario crear diferentes tipos de estructuras si se desea pasar mas de un argumento, también puede definirse mas de un solo parámetro o cambiar la forma de representar los datos pero estos son extensiones fuera del antiguo estándar pero mas intuitivos a la hora de implementar el cliente como el servidor. En este caso la función no toma argumentos pero aun así da el parámetro pero sin información útil. Para entregar la respuesta al cliente se usa el valor de retorno de la función. En este caso retornara una estructura process_info con los datos del proceso servidor.

Ahora se implementará la función de esta manera:

#include 
#include "process.h"

process_info *
get_process_info_1_svc(void *argp, struct svc_req *rqstp)
{
	static process_info  result;

	result.name = "process_server";
	result.pid = getpid();
	result.ppid = getppid();
	result.uid = getuid();
	result.gid = getgid();

	return &result;
}

Se muestra la función haciendo uso de las llamadas estándares de los sistemas UNIX para obtener la información del proceso. Ahora guardamos el código de implementación como process_server.c y ejecutamos el compilador para generar el ejecutable:

$ cc -o process_server process_server.c process_svc.c process_xdr.c

Una vez compilado podemos ejecutar el programa, pero no trabajara hasta que el cliente mande solicitudes, para ello en el siguiente post se implementara el programa cliente, el cual llamara al procedimiento del servidor y mostrara el resultado de esa información por la consola.