Search code examples
cunixposixipcmessage-queue

Message Queues IPC does not work properly


this code implements a simple client-server communication system using message queues in C.

local.h

#include <stdio.h>
#include <sys/types.h>
#include "sys/ipc.h"
#include <sys/msg.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>

#define SEED 'g'    /* seed for ftok */
#define SERVER 1L   /* message for the server */

typedef struct{
    long    msg_to; /* placed in the queue for */
    long    msg_fm;  /* placed in the queue by */
    char    buffer[BUFSIZ];
}MESSAGE;

client.c:

#include "local.h" 

int main(int argc, char const *argv[])
{
    key_t       key;
    pid_t       cli_pid;
    int         mid, n;
    MESSAGE     msg;
    static char m_key[10];

    cli_pid = getpid();
    
    if((key = ftok(".", SEED)) == -1){
        perror("Client: key generation");
        exit(1);
    }

    if((mid = msgget(key, 0)) == -1){
        mid = msgget(key, IPC_CREAT | 0660);
        printf("%d", mid);
        
        switch (fork()){
        case -1:
            perror("Client: fork");
            exit(3);
        case 0:
            sprintf(m_key, "%d", mid);
            execlp("./server", "server", m_key, NULL);
            perror("Client: exec");
            exit(4);
        }
    }
    while(1){
        msg.msg_to = SERVER;
        msg.msg_fm = cli_pid;

        write(fileno(stdout), "cmd>", 5);
        memset(msg.buffer, 0x0, BUFSIZ);
        n = read(fileno(stdin), msg.buffer, BUFSIZ);
        if(n == 0){
            break;
        }


        if(msgsnd(mid, &msg, sizeof(msg), 0) == -1){
            perror("Client: msgsend");
            exit(5);
        }
        if((n = msgrcv(mid, &msg, sizeof(msg), cli_pid, 0)) != -1){
            write(fileno(stdout), msg.buffer, strlen(msg.buffer));
        }
    }
    msgsnd(mid, &msg, 0, 0);
    exit(0);
}

server.c:

#include "local.h"

int main(int argc, char const *argv[])
{
    int     mid, n;
    MESSAGE msg;
    void    process_msg(char *, int);

    if (argc != 3) {
        fprintf(stderr, "Usage: %s msq_id &\n", argv[0]);
        exit(1);
    }
    while (1) {
        if ((n=msgrcv(mid, &msg, sizeof(msg), SERVER, 0)) == -1 ) {
            perror("Server: msgrcv");
            exit(2);
        } else if (n == 0){
            break;
        } else {
            process_msg(msg.buffer, strlen(msg.buffer));
            msg.msg_to = msg.msg_fm;
            msg.msg_fm = SERVER;
            if (msgsnd(mid, &msg, sizeof(msg), 0) == -1 ) {
                perror("Server: msgsnd");
                exit(3);
            }
        }
    }
    msgctl(mid, IPC_RMID, (struct msqid_ds *) 0 );
    exit(0);
}

void process_msg(char *b, int len) {
    int i;
    for (i = 0; i < len; ++i){
        if (isalpha(*(b + i))){
            *(b + i) = toupper(*(b + i));
        }
    }
}

If i try to compile these files with using this commands:

gcc -o server server.c
gcc -o client client.c

and run the files:

./server 123 &
./client

Server is running and waiting,

(base) user@PC:~/UNIX/mqueues$ ./server 123 &
[2] 93463
(base) user@PC:~/UNIX/mqueues$ Usage: ./server msq_id &
/waiting for message here/

then i am trying to send a message from client. However i get that error message from client:

(base) user@PC:~/UNIX/mqueues$ ./client
cmd>hello
Client: msgsend: Invalid argument

I'm probably doing something wrong, I'd be very grateful if you could help me. Thanks.


Solution

  • See:

    (base) user@PC:~/UNIX/mqueues$ ./server 123 &
    [2] 93463
    (base) user@PC:~/UNIX/mqueues$ Usage: ./server msq_id &
    /waiting for message here/
    

    That means that the server fails (message usage...). The first error is that you require to pass 3 arguments to the server, but the last & is not part of the arguments to the command but used by the shell to launch the command in background.

    Second error is that you must create the message queue at first in the server, prior to the call to msgrcv. If not, how the server would be able to read something?

    Third, what logic is behind all of this? The client forks the server, but it seems that you want to run the server by hand too. Forget about running the server from the client.