[Fila de mensagens] Filas de mensagens se comunicam com processos

0. Objeto IPC

        Além dos métodos mais primitivos de comunicação entre processos, sinais, pipes não nomeados e pipes nomeados, existem três métodos de comunicação entre processos, chamados de objetos IPC.

Classificação de objetos IPC: fila de mensagens, memória compartilhada, conjunto de semáforos

        O objeto IPC também abre uma área no espaço do kernel. Após a criação de cada objeto IPC, ele será definido como global e receberá um número. Contanto que o número exclusivo seja encontrado, a comunicação poderá ser realizada, para que processos não relacionados possam passar comunicação de objeto IPC.

        Após a criação do objeto IPC, ele ficará visível no sistema atual e sempre existirá, desde que não seja excluído ou o sistema seja desligado.

Visualize o objeto IPC criado:

ipcs Visualize todos os objetos IPC criados no sistema atual

ipcs -q Visualiza a fila de mensagens criada

ipcs -m Veja a memória compartilhada criada

ipcs -s Veja o semáforo criado

ipcrm exclui objetos IPC

        Por exemplo: ipcs -q msqid exclui a fila de mensagens denominada msqid

 

1. Visão geral da fila de mensagens

A fila de mensagens é uma lista vinculada de mensagens, armazenada na memória e mantida pelo kernel.

Características da fila de mensagens:

  • As mensagens na fila de mensagens são digitadas.
  • As mensagens na fila de mensagens são formatadas.
  • A fila de mensagens pode implementar consultas aleatórias de mensagens . As mensagens não precisam ser lidas na ordem de primeiro a entrar, primeiro a sair, você pode lê-las de acordo com o tipo de mensagem durante a programação.
  • Uma fila de mensagens permite que um ou mais processos escrevam ou leiam mensagens nela.
  • Assim como pipes não nomeados e pipes nomeados, quando as mensagens são lidas na fila de mensagens, os dados correspondentes na fila de mensagens serão excluídos.
  • Cada fila de mensagens possui um identificador de fila de mensagens, e o identificador da fila de mensagens é exclusivo em todo o sistema.
  • A fila de mensagens só será excluída quando o kernel for reiniciado ou a fila de mensagens for excluída manualmente. Se a fila de mensagens não for excluída manualmente, a fila de mensagens sempre existirá no sistema.

As restrições da fila de mensagens no Ubuntu 12.04 são as seguintes: (Basta entender)

  • O conteúdo de cada mensagem pode ter até 8K bytes
  • Cada fila de mensagens tem capacidade máxima de 16K bytes
  • O número máximo de filas de mensagens no sistema é 1.609
  • O número máximo de mensagens no sistema é 16384

2. Funções relacionadas à fila de mensagens

2.1 Gerar valor chave: função ftok

        O mecanismo de comunicação IPC fornecido pelo System V requer um valor chave, através do qual um identificador exclusivo de fila de mensagens pode ser obtido dentro do sistema.

        O valor da chave pode ser especificado manualmente ou obtido por meio da função ftok.

        Se vários processos se comunicarem através de objetos IPC, eles deverão encontrar um identificador exclusivo, e o identificador exclusivo será determinado pela chave, portanto, desde que a chave seja conhecida, vários processos poderão se comunicar.

Função ftok:

#include<sys/types.h>

#include<sys/ipc.h>

key_t ftok(const char *nome do caminho, int proj_id);

Função: Crie um valor-chave por meio do nome do arquivo e do valor alvo e retorne o valor

parâmetro:

        nome do caminho: qualquer nome de arquivo (nome do arquivo ou nome do diretório)

        proj_id: valor alvo, o intervalo geralmente é 0 ~ 127 (oito bits inferiores)

valor de retorno:

        Sucesso: valor chave

        Falha: -1

Se você usar a função ftok para obter o valor da chave, o valor da chave obtido será o arquivo correspondente ao primeiro parâmetro do ftok.

A informação é determinada em conjunto com o segundo parâmetro.

 Exemplo de código:

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>

int main()
{
    //使用ftok函数获取键值
    //只要保证ftok的第一个参数对应的文件和第二个参数值相同,则不管
    //程序运行多少遍或者多少个进程
    //键值一定是唯一的
    key_t mykey;
    if ((mykey = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }
    printf("key = %#x\n", mykey);
    return 0;
}

 Captura de tela de execução:

2.2 Criar fila de mensagens: função msgget

função msgget:

#include<sys/msg.h>

int msgget(key_t chave, int msgflg);

Função:

        Crie uma fila de mensagens e obtenha o ID da fila de mensagens

parâmetro:

        chave: valor da chave, o valor da chave exclusiva determina a fila de mensagens exclusiva

                Método 1: especifique um número arbitrário

                Método 2: Use a função ftok para obter o valor da chave (recomendado)

        msgflg: A permissão de acesso da fila de mensagens, geralmente definida como

                        IPC_CREAT | IPC_EXCL |0777

                        IPC_CREAT | 0777

valor de retorno:

        Sucesso: ID da fila de mensagens

        Falha: -1

Exemplo de código:

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<unistd.h>

int main()
{
    key_t mykey;
    if ((mykey = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }
    printf("mykey = %#x\n", mykey);

    int msqid;
    if ((msqid = msgget(mykey, IPC_CREAT | 0666)) == -1)
    {
        perror("fail to msgget");
        exit(1);
    }
    printf("msqid = %d\n", msqid);

    return 0;
}

Captura de tela de execução:

 2.3 Enviar mensagem: função msgsnd

função msgsnd:

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/msg.h>

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

Função: Enviar dados para a fila de mensagens especificada (operação de gravação)

parâmetro:

        msqid: ID da fila de mensagens 

        msgp: Os dados a serem gravados precisam ser definidos por você.

                estrutura estrutura mensagem{

                        long mtype; //Número da mensagem, deve ser maior que 0

                        char mtext[128]; //Texto da mensagem, vários membros podem ser definidos

                } MSG;

        msgsz: o tamanho do corpo da mensagem, excluindo o comprimento numérico da mensagem

        msgflg: sinalizador bit

                0 bloqueio

                IPC_NOWAIT sem bloqueio

valor de retorno:

        Sucesso: 0

        Falha: -1

Exemplo de código:

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<unistd.h>

#define N 128
typedef struct {
    long msg_type;//必须要有,且必须是long类型
    char msg_text[N];//可以有多个,自己定义
}MSG;
#define MSGTEXT_SIZE (sizeof(MSG) - sizeof(long))
int main()
{
    key_t key;
    if ((key = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }

    int msgid;
    if ((msgid = msgget(key, IPC_CREAT | 0777)) == -1)
    {
        perror("fail to msgget");
        exit(1);
    }

    MSG msg1 = { 1, "hello world" };
    MSG msg2 = { 2, "hello beijing" };
    MSG msg3 = { 3, "nihao zhangsan" };
    MSG msg4 = { 4, "lisi hello" };

    if (msgsnd(msgid, &msg1, MSGTEXT_SIZE, 0) == -1)
    {
        perror("fail to msgsnd");
        exit(1);
    }
    if (msgsnd(msgid, &msg2, MSGTEXT_SIZE, 0) == -1)
    {
        perror("fail to msgsnd");
        exit(1);
    }
    if (msgsnd(msgid, &msg3, MSGTEXT_SIZE, 0) == -1)
    {
        perror("fail to msgsnd");
        exit(1);
    }
    if (msgsnd(msgid, &msg4, MSGTEXT_SIZE, 0) == -1)
    {
        perror("fail to msgsnd");
        exit(1);
    }

    return 0;
}

Captura de tela de execução:

2.4 Receber mensagens: função msgrcv

Função msgrcv:

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/msg.h>

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, tipo de mensagem longo, int msgflg);

Função: Receber dados da fila de mensagens (operação de leitura), os dados recebidos serão excluídos da fila de mensagens

parâmetro:

        msqid: ID da fila de mensagens

        msgp: estrutura para salvar os dados recebidos

                estrutura struct_name{

                        long mytpe; //Número da mensagem, deve ser maior que 0

                        char metxt[128]; //Texto da mensagem, vários membros podem ser definidos        

                }

        msgsz: tamanho do corpo da mensagem

        msgtype: Defina qual mensagem receber

                 0 Leia uma vez na ordem escrita na fila de mensagens

                >0 Ler apenas a primeira mensagem na fila de mensagens com o número da mensagem do parâmetro atual

                <0 Leia apenas a menor primeira mensagem na fila de mensagens que seja menor ou igual ao valor absoluto do parâmetro atual

        msgflg: sinalizador bit

                 0 bloqueio

                 IPC_NOWAIT sem bloqueio

valor de retorno:

        Sucesso: Comprimento do corpo da mensagem recebida

        Falha: -1

Exemplo de código:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>

#define N 128
typedef struct {
    long msg_type;
    char msg_text[N];
}MSG;

#define MSGTEXT_SIZE (sizeof(MSG) - sizeof(long))

int main()
{
    key_t key;
    if ((key = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }

    int msgid;
    if ((msgid = msgget(key, IPC_CREAT | 0777)) == -1)
    {
        perror("fail to msgget");
        exit(1);
    }
    //通过msgrcv函数接收消息队列中的信息(读操作)
    //注意:如果没有第四个参数指定的消息时,,msgrcv函数会阻塞等待
    MSG msg;
    //如果第四个参数为>0,则获取当前值的消息类型的数据
    //if (msgrcv(msgid, &msg, MSGTEXT_SIZE, 2, 0) == -1)
    // 如果第四个参数<0,则获取当前值的绝对值内消息类型最小的数据
    //if (msgrcv(msgid, &msg, MSGTEXT_SIZE, -3, 0) == -1)
    //如果第四个参数为0,则按照先进先出的方式读取数据
    if (msgrcv(msgid, &msg, MSGTEXT_SIZE, 0, 0) == -1)
    {
        perror("fail to msgrcv");
        exit(1);
    }
    printf("recv_msg = %s\n", msg.msg_text);

    return  0;
}

Captura de tela de execução:

 2.5 Controle da fila de mensagens: função msgctl

Função msgctl:

#include<sys/mg.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

Função:

        Execute vários controles na fila de mensagens, como modificar as propriedades da fila de mensagens ou excluir a fila de mensagens

parâmetro:

        msqid: identificador da fila de mensagens

        cmd: Controle de funções de função

                IPC_RMID: Exclui a fila de mensagens indicada pelo msqid, removendo-a do sistema e destruindo estruturas de dados relacionadas.

                IPC_STAT: Armazena o valor atual de cada elemento na estrutura de dados relacionada ao msqid na estrutura apontada por buf.

                IPC_SET: Defina os elementos na estrutura de dados relacionada ao msqid para os valores correspondentes na estrutura apontada por buf.

        buf: O endereço do tipo de dados msqid_ds, usado para armazenar ou modificar os atributos da fila de mensagens.

valor de retorno:

        Sucesso: 0

        Falha: -1

Exemplo de código:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/msg.h>


int main()
{
    key_t key;
    if ((key = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }

    int msqid;
    if ((msqid = msgget(key, IPC_CREAT | 0777)) == -1)
    {
        perror("fail to msgget");
        exit(1);
    }
    printf("msqid = %d\n", msqid);
    system("ipcs -q");

    if ((msgctl(msqid, IPC_RMID, NULL)) == -1)
    {
        perror("fail to msgctl");
        exit(1);
    }
    system("ipcs -q");
    return 0;
}

Captura de tela de execução:

 Resumir:

        Como mecanismo IPC, a fila de mensagens fornece funções poderosas para enviar e receber mensagens entre processos. Ao usar filas de mensagens, aplicativos complexos de múltiplos processos podem ser construídos para obter transmissão segura e comunicação ordenada de dados, melhorando significativamente as capacidades de processamento simultâneo do sistema. Porém, você também deve estar ciente das limitações da fila de mensagens, como o tamanho da fila, o número total de mensagens armazenadas, etc., que podem impactar no desempenho da aplicação.

        Portanto, ao usar filas de mensagens, precisamos pesar suas vantagens e possíveis desafios para garantir que possamos manter um desempenho eficiente e uma operação estável, ao mesmo tempo em que atendemos às necessidades de negócios.

 

Acho que você gosta

Origin blog.csdn.net/crr411422/article/details/131421873
Recomendado
Clasificación