Colas de mensajes para la comunicación entre procesos msgget (), msgsend (), msgrcv (), msgctl ()

Cola de mensajes

1. La cola de mensajes proporciona un método para enviar un dato de un proceso a otro proceso
2. Cada bloque de datos se considera que tiene un tipo, y el bloque de datos recibido por el proceso del receptor puede tener diferentes valores de tipo

3. La diferencia entre las colas de mensajes y las canalizaciones es que las colas de mensajes se basan en mensajes, mientras que las canalizaciones se basan en flujos de bytes y la lectura de la cola de mensajes no es necesariamente primero en entrar, primero en salir.
4. La cola de mensajes tiene las mismas deficiencias que la canalización, es decir, la longitud máxima de cada mensaje está limitada (MSGMAX), la cantidad total de bytes en cada cola de mensajes está limitada (MSGMNB) y la cantidad total de colas de mensajes en el sistema también Un límite superior (MSGMNI), se pueden ver los tres parámetros:

 

1. ¿Qué es una cola de mensajes?

La cola de mensajes proporciona una forma de enviar un bloque de datos de un proceso a otro. Se considera que cada bloque de datos contiene un tipo, y el proceso de recepción puede recibir independientemente estructuras de datos que contienen diferentes tipos. Podemos evitar los problemas de sincronización y bloqueo de canalizaciones con nombre enviando mensajes. Pero la cola de mensajes es la misma que la tubería con nombre, cada bloque de datos tiene un límite de longitud máxima.

Linux usa las macros MSGMAX y MSGMNB para limitar la longitud máxima de un mensaje y la longitud máxima de una cola.

Segundo, use la cola de mensajes en Linux

Linux proporciona una serie de interfaces de funciones para colas de mensajes que nos permiten usarlo fácilmente para lograr la comunicación entre procesos. Su uso es similar a los otros dos mecanismos PIC del Sistema V, a saber, semáforo y memoria compartida.

 

1. La función msgget ()

Esta función se utiliza para crear y acceder a una cola de mensajes. Su prototipo es:

int msgget (clave_t, clave, int msgflg);

Al igual que con otros mecanismos de IPC, el programa debe proporcionar una clave para nombrar una cola de mensajes particular. msgflg es un indicador de permiso que indica el permiso de acceso de la cola de mensajes, que es lo mismo que el permiso de acceso del archivo. msgflg puede funcionar u operar con IPC_CREAT, lo que significa que se crea una cola de mensajes cuando la cola de mensajes nombrada por clave no existe. Si la cola de mensajes nombrada por clave existe, el indicador IPC_CREAT se ignora y solo se devuelve un identificador.

Devuelve un identificador (entero distinto de cero) de la cola de mensajes con el nombre de la clave y -1 en caso de error. 

2. La función msgsnd ()

Esta función se usa para agregar mensajes a la cola de mensajes. Su prototipo es:

int msgsend (int msgid, const void * msg_ptr, size_t msg_sz, int msgflg);

msgstr es el identificador de la cola de mensajes devuelto por la función msgget.

msg_ptr es un puntero al mensaje que se enviará, pero la estructura de datos del mensaje tiene ciertos requisitos. La estructura del mensaje señalada por el puntero msg_ptr debe ser una estructura que comience con una variable miembro larga. La función de recepción usará este miembro para determinar El tipo de mensaje. Entonces, la estructura del mensaje debe definirse de la siguiente manera: 


struct my_message {
    long int message_type;
    /* The data you wish to transfer */
};

msg_sz es la longitud del mensaje señalado por msg_ptr. Tenga en cuenta que es la longitud del mensaje, no la longitud de toda la estructura. En otras palabras, msg_sz es la longitud que no incluye la variable miembro del tipo de mensaje largo.

msgflg se usa para controlar lo que sucederá cuando la cola de mensajes actual esté llena o el mensaje de la cola alcance el límite de todo el sistema.

Si la llamada es exitosa, se colocará una copia de los datos del mensaje en la cola de mensajes y devuelve 0; si falla, devuelve -1.

 

 3. La función msgrcv ()

Esta función se utiliza para obtener mensajes de una cola de mensajes, su prototipo es

int msgrcv (int msgid, void * msg_ptr, size_t msg_st, long int msgtype, int msgflg);

msgid, msg_ptr, msg_st tienen la misma función que la función msgsnd ().

msgtype puede implementar una prioridad de recepción simple . Si msgtype es 0, obtenga el primer mensaje en la cola . Si su valor es mayor que cero, obtendrá el primer mensaje con el mismo tipo de mensaje. Si es menor que cero, obtenga el primer mensaje con un tipo igual o menor que el valor absoluto de msgtype.

msgflg se usa para controlar lo que sucede cuando no hay un tipo de mensaje correspondiente en la cola que se pueda recibir.

Cuando la llamada es exitosa, la función devuelve el número de bytes colocados en el búfer de recepción, el mensaje se copia en el búfer asignado por el usuario señalado por msg_ptr, y luego se elimina el mensaje correspondiente en la cola de mensajes. En caso de fallo, devuelve -1.

 

4. La función msgctl ()

Esta función se utiliza para controlar la cola de mensajes. Es similar a la función shmctl de la memoria compartida. Su prototipo es:

int msgctl (int msgid, int comando, struct msgid_ds * buf);

El comando es la acción a tomar, puede tomar 3 valores,

  • IPC_STAT: establezca los datos en la estructura msgid_ds en el valor asociado actual de la cola de mensajes, es decir, sobrescriba el valor de msgid_ds con el valor asociado actual de la cola de mensajes.
  • IPC_SET: si el proceso tiene permisos suficientes, establezca el valor asociado actual de la cola de mensajes al valor dado en la estructura msgid_ds
  • IPC_RMID: eliminar la cola de mensajes

Buf es un puntero a la estructura msgid_ds, que apunta a la estructura del modo de cola de mensajes y los derechos de acceso. La estructura msgid_ds incluye al menos los siguientes miembros: 

struct msgid_ds
{
    uid_t shm_perm.uid;
    uid_t shm_perm.gid;
    mode_t shm_perm.mode;
};

Devuelve 0 en caso de éxito y -1 en caso de error.

 

Tres, use la cola de mensajes para la comunicación entre procesos

Sin parar, después de presentar la definición de la cola de mensajes y la interfaz utilizable, echemos un vistazo a cómo permite que el proceso se comunique. Como los procesos no relacionados pueden comunicarse, escribiremos dos programas aquí, msgreceive () y msgsned () para indicar la recepción y el envío de información. En circunstancias normales, permitimos que ambos programas creen mensajes, pero solo después de que el receptor haya recibido el último mensaje, lo borra.

El código fuente del programa que recibe la información es msgreceive.c. El código fuente es:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/msg.h>
#include <errno.h>
 
struct msg_st
{
    long int msg_type;
    char text[BUFSIZ];
};
 
int main(int argc, char **argv)
{
    int msgid = -1;
    struct msg_st data;
    long int msgtype = 0;   // 注意1
 
    // 建立消息队列
    msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
    if (msgid == -1)
    {
        fprintf(stderr, "msgget failed width error: %d\n", errno);
        exit(EXIT_FAILURE);
    }
 
    // 从队列中获取消息,直到遇到end消息为止
    while (1)
    {
        if (msgrcv(msgid, (void *)&data, BUFSIZ, msgtype, 0) == -1)
        {
            fprintf(stderr, "msgrcv failed width erro: %d", errno);
        }
 
        printf("You wrote: %s\n", data.text);
 
        // 遇到end结束
        if (strncmp(data.text, "end", 3) == 0)
        {
            break;
        }
    }
 
    // 删除消息队列
    if (msgctl(msgid, IPC_RMID, 0) == -1)
    {
        fprintf(stderr, "msgctl(IPC_RMID) failed\n");
    }
 
    exit(EXIT_SUCCESS);
}

 El código fuente del archivo fuente msgsend.c del programa que envía la información es:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/msg.h>
#include <errno.h>
 
#define MAX_TEXT 512
 
struct msg_st
{
    long int msg_type;
    char text[MAX_TEXT];
};
 
int main(int argc, char **argv)
{
    struct msg_st data;
    char buffer[BUFSIZ];
    int msgid = -1;
 
    // 建立消息队列
    msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
    if (msgid == -1)
    {
        fprintf(stderr, "msgget failed error: %d\n", errno);
        exit(EXIT_FAILURE);
    }
 
    // 向消息队里中写消息,直到写入end
    while (1)
    {
        printf("Enter some text: \n");
        fgets(buffer, BUFSIZ, stdin);
        data.msg_type = 1; // 注意2
        strcpy(data.text, buffer);
 
        // 向队列里发送数据
        if (msgsnd(msgid, (void *)&data, MAX_TEXT, 0) == -1)
        {
            fprintf(stderr, "msgsnd failed\n");
            exit(EXIT_FAILURE);
        }
 
        // 输入end结束输入
        if (strncmp(buffer, "end", 3) == 0)
        {
            break;
        }
 
        sleep(1);
    }
 
    exit(EXIT_SUCCESS);
}

    

Cuatro, tipo de mensaje de análisis de ejemplo

Aquí se explica principalmente cuál es el tipo de mensaje. Preste atención a la variable msgtype (nota 1) definida en la función main () del archivo msgreceive.c, que se utiliza como el valor del parámetro del tipo de información recibida de la función msgrcv (). 0 significa obtener el primer mensaje disponible en la cola. Echemos un vistazo a la declaración data.msg_type = 1 (nota 2) en el bucle while en el archivo msgsend.c. Se utiliza para establecer el tipo de información enviada, es decir, el tipo de información enviada es 1. Entonces el programa msgreceive () puede recibir la información enviada por el programa msgsend ().

Si presta atención a 1, la instrucción en la función main () del archivo msgreceive.c cambia de long int msgtype = 0; a long int msgtype = 2; Información. Porque cuando se llama a la función msgrcv (), si msgtype (el cuarto parámetro) es mayor que cero, solo se obtendrá el primer mensaje con el mismo tipo de mensaje, el tipo de mensaje obtenido después de la modificación es 2 y el mensaje enviado por msgsend () El tipo es 1, por lo que no puede ser recibido por el programa msgreceive (). Vuelva a compilar el archivo msgreceive.c y ejecútelo nuevamente, el resultado es el siguiente:

Podemos ver que msgreceive no ha recibido información y salida, y cuando finaliza la entrada de msgsend, msgreceive no ha finalizado. A través del comando jobs, podemos ver que todavía se está ejecutando en segundo plano. 

 

Cinco, cola de mensajes y comparación de canalizaciones

Las colas de mensajes tienen muchas similitudes con las canalizaciones con nombre. De la misma manera que las canalizaciones con nombre, el proceso de comunicación de la cola de mensajes puede ser procesos no relacionados. Al mismo tiempo, todos envían datos mediante el envío y la recepción. En canalizaciones con nombre, write () se usa para enviar datos y read () se usa para recibir datos. En la cola de mensajes, msgsnd () se usa para enviar datos y msgrcv () se usa para recibir datos. Y tienen un límite de longitud máxima para cada dato.

En comparación con las canalizaciones con nombre, las ventajas de las colas de mensajes son:

1. La cola de mensajes también puede existir independientemente de los procesos de envío y recepción, eliminando así las dificultades que pueden surgir al abrir y cerrar la canalización con nombre sincronizada.

2. Al mismo tiempo, el problema de sincronización y bloqueo de canalizaciones con nombre también se puede evitar enviando mensajes, y no hay necesidad de proporcionar métodos de sincronización por el proceso mismo.

3. El programa receptor puede recibir datos selectivamente por tipo de mensaje, en lugar de recibirlos de manera predeterminada, como en las canalizaciones con nombre.

 

 

115 artículos originales publicados · Me gusta 29 · Visitantes 50,000+

Supongo que te gusta

Origin blog.csdn.net/huabiaochen/article/details/104988515
Recomendado
Clasificación