Why does msgrcv return Identifier removed?

292 views Asked by At

I'm learning IPCS and I try to send a message from a client to a server which will multiply it by 2 and send it back to the client using ftok, msgget, msgrcv, msgsnd and msgctl services of libc/linux. Here is my code:

ex1.h

#ifndef EX1_H
#define EX1_H

#define ID 2
#define PATH "./client.c"
struct msgbuf{
  long mtype;
  int mvalue;
} message, retour;
key_t cle;
int mes_id;
#endif

serveur.c

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

int main (int argc, char **argv){
  if((cle=ftok(PATH,ID)) == (key_t)-1){
    perror("Erreur lors de la création de la clé ");
    exit(EXIT_FAILURE);
  }
  if((mes_id = msgget(cle,IPC_CREAT | 0660 | IPC_EXCL)) == -1){
    perror("Erreur dans la création de la file de message ");
    exit(EXIT_FAILURE);
  }
  message.mtype = 1;
  if((msgrcv(mes_id, &message, sizeof(message), 1, 0)) == -1){
    perror("Erreur lors de la récéption du message ");
    exit(EXIT_FAILURE);
  }
  printf("Je suis le serveur et j'ai reçu %d.\n",message.mvalue);
  printf("J'effectue ma multiplication par 2 et renvoie le résultat.\n");
  retour.mtype = 3;
  retour.mvalue = message.mvalue * 2;
  if((msgsnd(mes_id, &retour, sizeof(retour), 0)) == -1){
    perror("Erreur lors de l'envoi du résultat ");
    exit(EXIT_FAILURE);
  }
  sleep(1);
  msgctl(mes_id,IPC_RMID, NULL);
  return EXIT_SUCCESS;
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "ex1.h"
#include <unistd.h>
int main (int argc, char **argv){
  if((cle=ftok(PATH, ID)) == (key_t)-1){
    perror("Erreur lors de la création de la clé ");
    exit(EXIT_FAILURE);
  }
  if((mes_id = msgget(cle, 0660 | IPC_EXCL)) == -1){
    perror("Erreur lors de la récupération du numéro de la file ");
    exit(EXIT_FAILURE);
  }
  message.mtype = 1;
  message.mvalue = 4;
  if((msgsnd(mes_id, &message, sizeof(message), 0)) == -1){
    perror("Erreur lors de l'envoi du message ");
    exit(EXIT_FAILURE);
  }
  retour.mtype = 3;
  sleep(2);
  if((msgrcv(mes_id, &retour, sizeof(retour), 3, 0)) == -1){
    perror("Erreur lors de la récéption du résultat ");
    exit(EXIT_FAILURE);
  }
  printf("Je suis le client et j'ai reçu %d\n", retour.mvalue);
  return EXIT_SUCCESS;
}

Due to line 23/24, I get Invalid argument (EINVAL) or Identifier removed (EIDRM) errors, but I don't understand what is the problem here.

1

There are 1 answers

0
Rachid K. On

"size" parameter of msgsnd()/msgrcv()

msgsnd() and msgrcv() receive the size of the data part of the message (the type field is not included). This should be used like this:

struct msgbuf{
  long mtype;
  int mvalue;
} message, retour;
[...]
msgrcv(mes_id, &retour, sizeof(retour.mvalue), 3, 0));
[...]
msgsnd(mes_id, &message, sizeof(message.mvalue), 0);

For more details, look at the examples sections in the manuals of msgrcv() and msgsnd().

Calls to sleep()

Suppress the calls to sleep() during the server/client message exchange as they are synchronized: when one sends a message, the other waits for the reception. As you call sleep(2) in the client before the last "receive", when it wakes up, the server may have removed the message queue. For your example, just put a sleep() at the end of the server right before the destruction of the queue.