martes, 13 de enero de 2009

Colas de Mensajes para linux

Las colas de mensajes, junto con los semáforos y la memoria compartida son los recursos compartidos que pone unix a disposición de los programas para que puedan intercambiarse información.

En c para unix se puede hacer que dos aplicaciones se envien mensajes, para ello se usa la cola de mensajes, en ella se envian los mensajes y en la otra aplicación se sacan en el orden en que entraron.
Se envian los mensajes clasificados en tipos, estos son enteros.

Les muestro dos aplicaciones que envían mensajes,

Aplicación 1
ej_cola1.c


#include
#include
#include
#include

// obligatoriamente como primer campo un long para indicar un identificador del mensaje.
// Los siguientes campos son la información que se quiera transmitir en el
// mensaje. Cuando más adelante, en el código, hagamos un cast a
// (struct msgbuf *), todos los campos de datos los verá el sistema como
// un único (char *)

struct Mi_Tipo_Mensaje
{
long Id_Mensaje;
int Dato_Numerico;
char Mensaje[10];
}Un_Mensaje;

int main(void)
{
key_t Clave1;
int Id_Cola_Mensajes;

// Igual que en cualquier recurso compartido (memoria compartida, semaforos
// o colas) se obtien una clave a partir de un fichero existente cualquiera
// y de un entero cualquiera. Todos los procesos que quieran compartir este
// semaforo, deben usar el mismo fichero y el mismo entero.

Clave1 = ftok ("/bin/ls", 33);
if (Clave1 == (key_t)-1)
{
printf("Error al obtener clave para cola mensajes");
return(0);
}

// Se crea la cola de mensajes y se obtiene un identificador para ella.
// El IPC_CREAT indica que cree la cola de mensajes si no lo está.
// el 0600 son permisos de lectura y escritura para el usuario que lance
// los procesos. Es importante el 0 delante para que se interprete en octal.

Id_Cola_Mensajes = msgget (Clave1, 0600 | IPC_CREAT);
if (Id_Cola_Mensajes == -1)
{
printf("Error al obtener identificador para cola mensajes");
return(0);
}

// Se rellenan los campos del mensaje que se quiere enviar.
// El Id_Mensaje es un identificador del tipo de mensaje. Luego se podrá
// recoger aquellos mensajes de tipo 1, de tipo 2, etc.
// Dato_Numerico es un dato que se quiera pasar al otro proceso. Se pone,
// por ejemplo 29.
// Mensaje es un texto que se quiera pasar al otro proceso.

Un_Mensaje.Id_Mensaje = 1;
Un_Mensaje.Dato_Numerico = 29;
strcpy (Un_Mensaje.Mensaje, "Hola");

// Se envia el mensaje. Los parámetros son:
// - Id de la cola de mensajes.
// - Dirección al mensaje, convirtiéndola en puntero a (struct msgbuf *)
// - Tamaño total de los campos de datos de nuestro mensaje, es decir
// de Dato_Numerico y de Mensaje
// - Unos flags. IPC_NOWAIT indica que si el mensaje no se puede enviar
// (habitualmente porque la cola de mensajes esta llena), que no espere
// y de un error. Si no se pone este flag, el programa queda bloqueado
// hasta que se pueda enviar el mensaje.

msgsnd (Id_Cola_Mensajes, (struct msgbuf *)&Un_Mensaje,
sizeof(Un_Mensaje.Dato_Numerico)+sizeof(Un_Mensaje.Mensaje),
IPC_NOWAIT);

// Se recibe un mensaje del otro proceso. Los parámetros son:
// - Id de la cola de mensajes.
// - Dirección del sitio en el que queremos recibir el mensaje,
// convirtiéndolo en puntero a (struct msgbuf *).
// - Tamaño máximo de nuestros campos de datos.
// - Identificador del tipo de mensaje que queremos recibir. En este caso
// se quiere un mensaje de tipo 2. Si ponemos tipo 1, se extrae el mensaje
// que se acaba de enviar en la llamada anterior a msgsnd().
// - flags. En este caso se quiere que el programa quede bloqueado hasta
// que llegue un mensaje de tipo 2. Si se pone IPC_NOWAIT, se devolvería
// un error en caso de que no haya mensaje de tipo 2 y el programa
// continuaría ejecutándose.

msgrcv (Id_Cola_Mensajes, (struct msgbuf *)&Un_Mensaje,
sizeof(Un_Mensaje.Dato_Numerico) + sizeof(Un_Mensaje.Mensaje),
2, 0);

printf("Recibido mensaje tipo 2 \n");
printf("Dato_Numerico = %i \n",Un_Mensaje.Dato_Numerico);
printf("Mensaje = %s \n",Un_Mensaje.Mensaje);


// Se borra y cierra la cola de mensajes.
// IPC_RMID indica que se quiere borrar. El puntero del final son datos
// que se quieran pasar para otros comandos. IPC_RMID no necesita datos,
// así que se pasa un puntero a NULL.

msgctl (Id_Cola_Mensajes, IPC_RMID, (struct msqid_ds *)NULL);
}

Aplicación 1
ej_cola2.c


#include
#include
#include
#include

// Estructura para los mensajes que se quieren enviar y/o recibir. Deben llevar
// obligatoriamente como primer campo un long para indicar un identificador
// del mensaje.
// Los siguientes campos son la información que se quiera transmitir en el
// mensaje. Cuando más adelante, en el código, hagamos un cast a
// (struct msgbuf *), todos los campos de datos los verá el sistema como
// un único (char *)

struct Mi_Tipo_Mensaje
{
long Id_Mensaje;
int Dato_Numerico;
char Mensaje[10];
}Un_Mensaje;


int main(void)
{
key_t Clave1;
int Id_Cola_Mensajes;

// Igual que en cualquier recurso compartido (memoria compartida, semaforos
// o colas) se obtien una clave a partir de un fichero existente cualquiera
// y de un entero cualquiera. Todos los procesos que quieran compartir este
// semaforo, deben usar el mismo fichero y el mismo entero.

Clave1 = ftok ("/bin/ls", 33);
if (Clave1 == (key_t)-1)
{
printf("Error al obtener clave para cola mensajes \n");
return(0);
}

// Se crea la cola de mensajes y se obtiene un identificador para ella.
// El IPC_CREAT indica que cree la cola de mensajes si no lo está.
// el 0600 son permisos de lectura y escritura para el usuario que lance
// los procesos. Es importante el 0 delante para que se interprete en
// octal.

Id_Cola_Mensajes = msgget (Clave1, 0600 | IPC_CREAT);
if (Id_Cola_Mensajes == -1)
{
printf("Error al obtener identificador para cola mensajes \n");
return(0);
}

// Se recibe un mensaje del otro proceso. Los parámetros son:
// - Id de la cola de mensajes.
// - Dirección del sitio en el que queremos recibir el mensaje,
// convirtiéndolo en puntero a (struct msgbuf *).
// - Tamaño máximo de nuestros campos de datos.
// - Identificador del tipo de mensaje que queremos recibir. En este caso
// se quiere un mensaje de tipo 1, que es el que envia el proceso cola1.cc
// - flags. En este caso se quiere que el programa quede bloqueado hasta
// que llegue un mensaje de tipo 1. Si se pone IPC_NOWAIT, se devolvería
// un error en caso de que no haya mensaje de tipo 1 y el programa
// continuaría ejecutándose.

msgrcv (Id_Cola_Mensajes, (struct msgbuf *)&Un_Mensaje,
sizeof(Un_Mensaje.Dato_Numerico) + sizeof(Un_Mensaje.Mensaje),
1, 0);

printf("Recibido mensaje tipo 1 \n");
printf("Dato_Numerico = %i \n",Un_Mensaje.Dato_Numerico);
printf("Mensaje = %s \n",Un_Mensaje.Mensaje);

// Se rellenan los campos del mensaje que se quiere enviar.
// El Id_Mensaje es un identificador del tipo de mensaje. Luego se podrá
// recoger aquellos mensajes de tipo 1, de tipo 2, etc.
// Dato_Numerico es un dato que se quiera pasar al otro proceso. Se pone,
// por ejemplo 13.
// Mensaje es un texto que se quiera pasar al otro proceso.
//
Un_Mensaje.Id_Mensaje = 2;
Un_Mensaje.Dato_Numerico = 13;
strcpy (Un_Mensaje.Mensaje, "Adios");

// Se envia el mensaje. Los parámetros son:
// - Id de la cola de mensajes.
// - Dirección al mensaje, convirtiéndola en puntero a (struct msgbuf *)
// - Tamaño total de los campos de datos de nuestro mensaje, es decir
// de Dato_Numerico y de Mensaje
// - Unos flags. IPC_NOWAIT indica que si el mensaje no se puede enviar
// (habitualmente porque la cola de mensajes esta llena), que no espere
// y de un error. Si no se pone este flag, el programa queda bloqueado
// hasta que se pueda enviar el mensaje.

msgsnd (Id_Cola_Mensajes, (struct msgbuf *)&Un_Mensaje,
sizeof(Un_Mensaje.Dato_Numerico)+sizeof(Un_Mensaje.Mensaje),
IPC_NOWAIT);
}


Para correr los archivos .c se compilan en consola con:
# gcc  ej_sem1.c -o ej_sem1

Y para correrlo:
# ./ej_sem1


Lo mismo con el segundo archivo, se corre cada uno en una consola diferente y veremos como funcionan los semáforos del sistema operativo linux/unix.

Para mayor referencia:
http://www.chuidiang.com/clinux/ipcs/colas.php

0 comentarios:

 
;