Conectar Drupal con servicios externos

La inmensa mayoría de las aplicaciones y/o páginas web que realicemos van a requerir de conexiones a ciertas máquinas para solicitar servicios y/o información. Y esta situaciación, a dia de hoy, en el que la información está distribuida y segmentada en diferentes máquinas, se vuelve una tarea habitual.

Por tanto, no es raro que una máquina que corra bajo un S.O. privativo solicite datos a otra máquina que se encuentre en la otra parte del mundo, que corra bajo un S.O. libre; o vicebersa.

Esta comunicación se puede dar gracias al protocolo de transmisión TCP, encargado de traer y llevar la información de una máquina a otra sirviendose de los diferentes protocolos de servicios existentes, como son HTTP o SMTP.

No será extraño que un proyecto en el que estemos trabajando, por ejemplo, un proyecto en Drupal, requiera de ciertas conexiones que se deban de producir en momentos determinados para cumplir objetivos concretos.

En este post vamos a tratar de solventar este problema, creando un sencillo ejemplo: desde una web creada en Drupal vamos a solicitar a una máquina externa (servidor escrito en Java) que nos de un número aleatorio. Cuando tengamos el resultado lo mostraremos en la página web. (El ejemplo pretende ilustrar como se realizan las conexiones, existen multitud de maneras para presentar un número aleatorio).

Creando el servidor que escuchará a Drupal

Lo primero que debemos de saber es que para realizar una conexión entre dos máquinas debemos de saber la IP de la máquina objetivo, así como el puerto al que vamos a solicitar servicio. Vamos a definir un programa muy sencillo que actuará como servidor. Este programa estará construido en Java y correrá bajo una máquina con S.O. privativo.

Dividimos la aplicación servidor en dos clases, la clase que define al propio servidor, y la clase que define la actuación del servidor al recibir un cliente nuevo. La clase que se encarga de actuar como receptor de conexiones entrantes será Server.java

public class Server{
	
	private static final int PUERTO = 9090;
		
	public static void main(String[] args) {
		ServerSocket server;
		ThreadGroup grupoClientes = new ThreadGroup("Clientes");
		try {
			server = new ServerSocket(PUERTO);
			while (true) {
				HiloCliente cliente = new HiloCliente(grupoClientes, "Hilo ", server.accept());
				cliente.start();
			}
			server.close();
		} catch (IOException e) {
			System.out.println(e.getMessage());
			System.out.print(e.getStackTrace());
		}
	}
}

La clase que gestiona las operaciones de cada uno de los clientes será HiloCliente.java

public class HiloCliente extends Thread {

	public Socket socket;
	public ThreadGroup grupoHilos;
	public String nombre;
	BufferedWriter bw;
	
	public HiloCliente(ThreadGroup group, String name, Socket socket) throws IOException {
		super(group, name);
		this.socket = socket;
		this.grupoHilos = group;
		this.nombre = name+" "+socket.getInetAddress();
		bw = new BufferedWriter(new OutputStreamWriter(this.socket.getOutputStream()));
	}
	
	@Override
	public void run() {
		super.run();
		try {
			int numero = (int) (Math.random*1000);
			System.out.println("El número aleatorio es: "+numero);
			bw.write(numero+””);
			bw.flush();
			bw.close();
			socket.close();		
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

Como vemos, es un programa muy sencillo que realiza las siguientes operaciones:

  • Nada más iniciarse, se mete en un bucle infinito en el que queda a la escucha de nuevas conexiones entrantes. Por supuesto, no tomar este ejemplo como un programa definitivo, es orientativo.
  • Por cada solicitud de conexión que recibe la máquina en el puerto especificado, el programa abre un nuevo Thread para gestionar las operaciones que se necesiten realizar con cada cliente.

Expandiendo Drupal a servicios externos

Hasta aquí nos hemos metido en el contexto, ahora vamos a conectar nuestra instalación de Drupal con esta máquina, y solicitarle un número. Para ello, vamos a crear nuestro propio módulo de Drupal, el cual se encargará de que cada vez que se visualice una dirección concreta, solicite al programa Java un número aleatorio y lo muestre como resultado. En nuestro caso, el módulo se llamará num_aleatorios_bikuma.

Para ello creamos los archivos num_aleatorios_bikuma.info y module. Una vez creados, vamos a trabajar en la definición del módulo, es decir en el archivo “.module”. Lo primero que vamos a hacer para cumplir los requisitos funcionales de este supuesto es crear un hook_menu para una url concreta.

function num_aleatorios_bikuma_menu() {
	$items['numero'] = array(
		'title' => “Número aleatorio”
		'page callback' => 'conectar_numeros_aleatorios',
		'access callback' => true,
  		'type' => MENU_NORMAL_ITEM,
	);
	return $items;
}

Una vez creado el menú de acceso a nuestra página de resultado, vamos a crear la funcionalidad. El método que nos dará esta funcionalidad será “conectar_numeros_aleatorios”. Vamos a presentarlo primero, después explicaremos el proceso.

function conectar_numeros_aleatorios(){
	$socket = fsockopen($ip, $puerto) or die("No se ha podido establecer la conexion");
	stream_set_timeout($socket, 20);
	$mensaje = fread($socket, 2048);
	$info= stream_get_meta_data($socket); 
	fflush($socket);	
	if($info['timed_out'])	$mensaje = “No se produjo respuesta en tiempo válido.”;
	fclose($socket);
	$output = array(
		'#markup' => "El número aleatorio recibido es: ".$mensaje,
	);
	return $output;		
}

Analicemos el código.

  • Lo primero ha sido establecer un nuevo socket de conexión con la máquina objetivo, para ello hemos tenido que especificar por parámetros la dirección IP de la máquina y el puerto de destino. Nos hemos servido de la función fsockopen.
  • Seguido hemos establecido un tiempo de espera máximo para terminar la conexión.
  • A continuación procedemos a leer desde el socket, con una longitud especificada por parámetro, en este caso 2048 bits, 2Kb.
  • Capturamos la metainformación generada durante el tiempo que ha permanecido abierto el socket. Si en este array de información existe la clave “timed_out”, indicará que la lectura terminó debido a un exceso de tiempo.
  • Devolvemos el array de contenido para que Drupal se encargue de pintarlo en la web como resultado final.

Pequeños apuntes al respecto

Como hemos visto, conectar una instalación de Drupal con un servicio externo a través de socket no es complejo, sin embargo, existen una serie de consideraciones que hemos de tener en cuenta.

En PHP existen diferentes maneras de abrir un socket. Se puede abrir un socket a bajo nivel mediante las funciones socket_create() y socket_connect(), o podemos utilizar una función abstraida como es fsockopen. Para diferenciarlos, se podría decir que fsockopen es aproximadamente el equivalente a abrir un socket con socket_create() e iniciar la conexión con socket_connect().

Utilizar uno u otro, o alguna del resto de opciones debería de ser una opción meditada, ya que las ventajas que aporta fsockopen sobre la otra metodología son la capacidad de abstracción de la manera en la que se transmiten los datos, sin embargo, perdemos la capacidad de control que tenemos sobre el socket. Con socket_create() podremos especificar el protocolo a ser empleado durante la conexión o el tipo de socket a utilizar, es decir, si el protocolo está basado en TCP, UDP, ICMP, etc.

<p><a class="theme_btn" href="http://www.bikuma.com/diseno-y-desarrollo-web?utm_source=Blog&amp;utm_me...">Quiero dar ofrecer un servicio en mi web/app</a></p>