Comment utiliser mqueue (file d'attente de messages) dans un programme c sur un système Linux?
Je cherche de bons exemples de code qui peuvent montrer comment cela est fait de manière correcte et appropriée, peut-être un guide pratique.
Ce qui suit est un exemple simple d'un serveur qui reçoit des messages des clients jusqu'à ce qu'il reçoive un message de "sortie" lui disant d'arrêter.
Le code pour serveur:
#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;
}
Le code pour le client:
#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;
}
L'en-tête commun:
#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_ */
Compilation:
gcc -o server server.c -lrt
gcc -o client client.c -lrt
#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)
copie sizeof(int)
octets du tampon &a
dans ce cas, il ne porte pas le pointeur de la variable a
, mais porte la valeur de la variable a
d'un processus à un autre. La mise en œuvre est correcte.
Code comme ci-dessous pour votre référence:
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);
}
Compilez chacun des fichiers source pour obtenir un exécutable d'écriture et un exécutable de lecture. Comme ci-dessous ::
gcc -o MQsender IPC_msgq_send.c
gcc -o MQreceiver IPC_msgq_rcv.c
En exécutant chacun des binaires, vous pouvez envoyer le message et lire le message dans la file d'attente de messages. Essayez également de voir l'état de la file d'attente des messages, en exécutant la commande (à différents états de la file d'attente):
ipcs -q
Pour votre système Linux, vous pouvez connaître tous les détails des mécanismes IPC et les files d'attente disponibles, etc., en utilisant:
ipcs -a