Como uso a MQUEUE no programa CA em um sistema baseado em Linux?
Pergunta
Como uso o MQUEUE (fila de mensagens) no programa CA em um sistema baseado em Linux?
Estou procurando alguns bons exemplos de código que possam mostrar como isso é feito de uma maneira correta e correta, talvez um Howto.
Solução
A seguir, é apresentado um exemplo simples de um servidor que recebe mensagens de clientes até receber uma mensagem de "saída" dizendo para ele parar.
O código para o servidor:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <mqueue.h>
#include "common.h"
int main(int argc, char **argv)
{
mqd_t mq;
struct mq_attr attr;
char buffer[MAX_SIZE + 1];
int must_stop = 0;
/* initialize the queue attributes */
attr.mq_flags = 0;
attr.mq_maxmsg = 10;
attr.mq_msgsize = MAX_SIZE;
attr.mq_curmsgs = 0;
/* create the message queue */
mq = mq_open(QUEUE_NAME, O_CREAT | O_RDONLY, 0644, &attr);
CHECK((mqd_t)-1 != mq);
do {
ssize_t bytes_read;
/* receive the message */
bytes_read = mq_receive(mq, buffer, MAX_SIZE, NULL);
CHECK(bytes_read >= 0);
buffer[bytes_read] = '\0';
if (! strncmp(buffer, MSG_STOP, strlen(MSG_STOP)))
{
must_stop = 1;
}
else
{
printf("Received: %s\n", buffer);
}
} while (!must_stop);
/* cleanup */
CHECK((mqd_t)-1 != mq_close(mq));
CHECK((mqd_t)-1 != mq_unlink(QUEUE_NAME));
return 0;
}
O código para o cliente:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <mqueue.h>
#include "common.h"
int main(int argc, char **argv)
{
mqd_t mq;
char buffer[MAX_SIZE];
/* open the mail queue */
mq = mq_open(QUEUE_NAME, O_WRONLY);
CHECK((mqd_t)-1 != mq);
printf("Send to server (enter \"exit\" to stop it):\n");
do {
printf("> ");
fflush(stdout);
memset(buffer, 0, MAX_SIZE);
fgets(buffer, MAX_SIZE, stdin);
/* send the message */
CHECK(0 <= mq_send(mq, buffer, MAX_SIZE, 0));
} while (strncmp(buffer, MSG_STOP, strlen(MSG_STOP)));
/* cleanup */
CHECK((mqd_t)-1 != mq_close(mq));
return 0;
}
o comum cabeçalho:
#ifndef COMMON_H_
#define COMMON_H_
#define QUEUE_NAME "/test_queue"
#define MAX_SIZE 1024
#define MSG_STOP "exit"
#define CHECK(x) \
do { \
if (!(x)) { \
fprintf(stderr, "%s:%d: ", __func__, __LINE__); \
perror(#x); \
exit(-1); \
} \
} while (0) \
#endif /* #ifndef COMMON_H_ */
Compilação:
gcc -o server server.c -lrt
gcc -o client client.c -lrt
Outras dicas
#include <stdio.h>
#include <fcntl.h>
#include <mqueue.h>
int main(int argc, char *argv[])
{
mqd_t mq; // message queue
struct mq_attr ma; // message queue attributes
int status = 0;
int a = 5;
int b = 0;
printf("a = %d, b = %d\n", a, b);
// Specify message queue attributes.
ma.mq_flags = 0; // blocking read/write
ma.mq_maxmsg = 16; // maximum number of messages allowed in queue
ma.mq_msgsize = sizeof(int); // messages are contents of an int
ma.mq_curmsgs = 0; // number of messages currently in queue
// Create the message queue with some default settings.
mq = mq_open("/test_queue", O_RDWR | O_CREAT, 0700, &ma);
// -1 indicates an error.
if (mq == -1)
{
printf("Failed to create queue.\n");
status = 1;
}
if (status == 0)
{
status = mq_send(mq, (char *)(&a), sizeof(int), 1);
}
if (status == 0)
{
status = mq_receive(mq, (char *)(&b), sizeof(int), NULL);
}
if ((status == 0) && (mq_close(mq) == -1))
{
printf("Error closing message queue.\n");
status = 1;
}
if ((status == 0) && (mq_unlink("test_queue") == -1))
{
printf("Error deleting message queue.\n");
status = 1;
}
printf("a = %d, b = %d\n", a, b);
return status;
}
mq_send(mq, (char *)(&a), sizeof(int), 1)
cópias sizeof(int)
bytes do buffer &a
Nesse caso, ele não carrega o ponteiro da variável a
, mas carrega o valor da variável a
de um processo para outro processo. A implementação está certa.
Código como abaixo para sua referência:
IPC_MSGQ_RCV.C
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 128
void die(char *s)
{
perror(s);
exit(1);
}
struct msgbuf
{
long mtype;
char mtext[MAXSIZE];
};
void main()
{
int msqid;
key_t key;
struct msgbuf rcvbuffer;
key = 1234;
if ((msqid = msgget(key, 0666)) < 0)
die("msgget()");
//Receive an answer of message type 1.
if (msgrcv(msqid, &rcvbuffer, MAXSIZE, 1, 0) < 0)
die("msgrcv");
printf("%s\n", rcvbuffer.mtext);
exit(0);
}
Ipc_msgq_send.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXSIZE 128
void die(char *s)
{
perror(s);
exit(1);
}
struct msgbuf
{
long mtype;
char mtext[MAXSIZE];
};
main()
{
int msqid;
int msgflg = IPC_CREAT | 0666;
key_t key;
struct msgbuf sbuf;
size_t buflen;
key = 1234;
if ((msqid = msgget(key, msgflg )) < 0) //Get the message queue ID for the given key
die("msgget");
//Message Type
sbuf.mtype = 1;
printf("Enter a message to add to message queue : ");
scanf("%[^\n]",sbuf.mtext);
getchar();
buflen = strlen(sbuf.mtext) + 1 ;
if (msgsnd(msqid, &sbuf, buflen, IPC_NOWAIT) < 0)
{
printf ("%d, %ld, %s, %d \n", msqid, sbuf.mtype, sbuf.mtext, (int)buflen);
die("msgsnd");
}
else
printf("Message Sent\n");
exit(0);
}
Compile cada um dos arquivos de origem, para obter um escritor executável e executável ao leitor. Como abaixo::
gcc -o mqsender ipc_msgq_send.c
gcc -o mqreceiver ipc_msgq_rcv.c
Executando cada um dos binários, você pode enviar a mensagem e ler a mensagem da fila da mensagem. Além disso, tente ver o estado da fila de mensagens, executando o comando (em diferentes estados da fila):
IPCS -Q
Para o seu sistema Linux, você pode conhecer todos os detalhes dos mecanismos do IPC e filas disponíveis etc. usando:
IPCS -A