Alejandro Harrison
Alejandro Harrison

Reputation: 21

How does a receiving process actually receive a process from a sender process via message queues?

I'm working on a project with a sender and receiver process using shared memory and a message queue. For the life of me, I cannot get the receiver process to receive the file, but i can't figure out what's actually going wrong. It seems like it's actually not getting the file or it's just stuck in an infinite loop.

So I understand that using a message queue, you need to attach to the message queue, using the message queue id. Then when you send a message, it goes to the message queue, and the receiver can receive it from that message queue. However that's what i'm doing (i think) in my code, but as mentioned before the receiver process doesn't seem to get the file. So am I wrong in how a process receives a message and thus implementing the code wrong? Any help would be greatly appreciated, as my professor just kinda threw us into this with no explanation on how to do this, so i've been trying to teach myself. This is what i have for my code:

message.h:

#include <stdio.h>
/* The information type */

#define SENDER_DATA_TYPE 1

/* The done message */
#define RECV_DONE_TYPE 2

/**
 * The message structure
 */


struct message
{
        /* The message type */
        long mtype;

        /* How many bytes in the message */
        int size;

        /**
         * Prints the structure
         * @param fp - the file stream to print to
         */

        void print(FILE *fp)
        {
                fprintf(fp, "%ld %d", mtype, size);
        }
};

Sender.cpp:

#include <iostream>
#include <sys/shm.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "msg.h"    /* For the message struct */

/* The size of the shared memory chunk */
#define SHARED_MEMORY_CHUNK_SIZE 1000

/* The ids for the shared memory segment and the message queue */
 int shmid, msqid;

/* The pointer to the shared memory */
 void* sharedMemPtr;

/**
 * Sets up the shared memory segment and message queue
 * @param shmid - the id of the allocated shared memory
 * @param msqid - the id of the shared memory
 */

 void init(int& shmid, int& msqid, void*& sharedMemPtr)
{
        std::cout<<"Creating key"<<std::endl;
        key_t key = ftok("keyfile.txt", 'a');
        std::cout<<"Key created"<<std::endl;

        shmid =shmget(key,SHARED_MEMORY_CHUNK_SIZE, 0644|IPC_CREAT);
        std::cout<<"allocated shared memory"<<std::endl;

        sharedMemPtr = shmat(shmid,NULL,0);
        std::cout<<"Attached to shared memory"<<std::endl;

        msqid = msgget(key,0644|IPC_CREAT);
        std::cout<<"Attahed to message queue"<<std::endl;
}

 void cleanUp(const int& shmid, const int& msqid, void* sharedMemPtr)
{
        /* TODO: Detach from shared memory */
        shmdt(sharedMemPtr);
}

/**
 * The main send function
 * @param fileName - the name of the file
 */
void send(const char* fileName)
{
        /* Open the file for reading */
        FILE* fp = fopen(fileName, "r");

        /* A buffer to store message we will send to the receiver. */
        message sndMsg;

        /* A buffer to store message received from the receiver. */
        message rcvMsg;

        /* Was the file open? */
        if(!fp)
        {
                perror("fopen");
                exit(-1);
        }

        /* Read the whole file */
        while(!feof(fp))
        {
    if((sndMsg.size = fread(sharedMemPtr, sizeof(char), SHARED_MEMORY_CHUNK_SIZE, fp)) < 0)
                {
                        perror("fread");
                        exit(-1);
                }

                /* TODO: Send a message to the receiver telling him that the data is ready
                 * (message of type SENDER_DATA_TYPE)
                 */

                sndMsg.mtype = SENDER_DATA_TYPE;
                sndMsg.size = 0;
                msgsnd(msqid,&sndMsg,sizeof(sndMsg),0);
                std::cout<<"Sent data ready message"<<std::endl;
                /* TODO: Wait until the receiver sends us a message of type RECV_DONE_TYPE telling us
                 * that he finished saving the memory chunk.
                 */
                std::cout<<"Waiting for reciever message"<<std::endl;
                msgrcv(msqid,&rcvMsg,0,RECV_DONE_TYPE,0);
                std::cout<<"Message received"<<std::endl;
        }

       /** TODO: once we are out of the above loop, we have finished sending the file.
          * Lets tell the receiver that we have nothing more to send. We will do this by
          * sending a message of type SENDER_DATA_TYPE with size field set to 0.
          */
        sndMsg.size =0;
        sndMsg.mtype = SENDER_DATA_TYPE;
        std::cout<<"Sending empty message"<<std::endl;
        msgsnd(msqid,&sndMsg,sizeof(sndMsg),0);
        std::cout<<"Empty message sent"<<std::endl;
        /* Close the file */
        fclose(fp);

}

int main(int argc, char** argv)
{

        /* Check the command line arguments */
        if(argc < 2)
        {
                fprintf(stderr, "USAGE: %s <FILE NAME>\n", argv[0]);
                exit(-1);
        }

        /* Connect to shared memory and the message queue */
        init(shmid, msqid, sharedMemPtr);

        /* Send the file */
        send(argv[1]);

        /* Cleanup */
        cleanUp(shmid, msqid, sharedMemPtr);

        return 0;
}

Receiver.cpp:

#include <iostream>
#include <sys/shm.h>
#include <sys/msg.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "msg.h"    /* For the message struct */


/* The size of the shared memory chunk */
#define SHARED_MEMORY_CHUNK_SIZE 1000

/* The ids for the shared memory segment and the message queue */
 int shmid, msqid;

/* The pointer to the shared memory */
 void *sharedMemPtr;

/* The name of the received file */
const char recvFileName[] = "recvfile";

/**
 * Sets up the shared memory segment and message queue
 * @param shmid - the id of the allocated shared memory
 * @param msqid - the id of the shared memory
 * @param sharedMemPtr - the pointer to the shared memory
 */

 void init(int& shmid, int& msqid, void*& sharedMemPtr)
{
        std::cout<<"Creating key"<<std::endl;
        key_t key = ftok("keyfile.txt", 'a');

        shmid =shmget(key,SHARED_MEMORY_CHUNK_SIZE, 0644 | IPC_CREAT);
        std::cout<<"allocated shared memory"<<std::endl;

        sharedMemPtr = shmat(shmid,NULL,0);
        std::cout<<"Attached to shared memory"<<std::endl;

        msqid = msgget(key,0644 | IPC_CREAT);
        std::cout<<"Attahed to message queue"<<std::endl;
}

void mainLoop()
{
        /* The size of the mesage */
        int msgSize =0;

        /* Open the file for writing */
        FILE* fp = fopen(recvFileName, "w");

        /* Error checks */
        if(!fp)
        {
                perror("fopen");
                exit(-1);
        }

        std::cout<<"Waiting for message"<<std::endl;

    /* TODO: Receive the message and get the message size. The message will
     * contain regular information. The message will be of SENDER_DATA_TYPE
     * (the macro SENDER_DATA_TYPE is defined in msg.h).  If the size field
     * of the message is not 0, then we copy that many bytes from the shared
     * memory region to the file. Otherwise, if 0, then we close the file and
     * exit.
     * Keep receiving until the sender set the size to 0, indicating that
     * there is no more data to send
         */

  while(msgSize != 0){

        message recvdMsg;
        msgrcv(msqid,&recvdMsg,sizeof(recvdMsg),SENDER_DATA_TYPE,0);
        msgSize  = recvdMsg.size;
        std::cout<<"Entering main loop"<<std::endl;

        /* If the sender is not telling us that we are done, then get to work */

                if(msgSize != 0)
                {
                        /* Save the shared memory to file */
                        if(fwrite(sharedMemPtr, sizeof(char), msgSize, fp) < 0)
                        {
                                perror("fwrite");
                        }

                        /* TODO: Tell the sender that we are ready for the next file chunk.
                         * I.e. send a message of type RECV_DONE_TYPE (the value of size field
                         * does not matter in this case).
                         */
                message sentMsg;
                sentMsg.mtype = RECV_DONE_TYPE;
                std::cout<<"Ready for next file chunk"<<std::endl;
                msgsnd(msqid,&sentMsg,0,0);
                std::cout<<"Ready message sent"<<std::endl;
}

                        /* We are done */
                else
                {
                        /* Close the file */
                        fclose(fp);
                }
        }
}

void cleanUp(const int& shmid, const int& msqid, void* sharedMemPtr)
{

        printf("Detaching from shared memory\n");
        shmdt(sharedMemPtr);
        printf("Deallocating shared memory chunk\n");
        shmctl(shmid,IPC_RMID,NULL);
        printf("deallocating message queue\n");
        msgctl(msqid,IPC_RMID,NULL);
}

void ctrlCSignal(int signal)
{
        /* Free system V resources */
        cleanUp(shmid, msqid, sharedMemPtr);
}

int main(int argc, char** argv)
{

        /* TODO: Install a signal handler
         * In a case user presses Ctrl-c your program should delete message
         * queues and shared memory before exiting. You may add the cleaning functionality
         * in ctrlCSignal().
         */
        signal(SIGINT, ctrlCSignal);


        /* Initialize */
        init(shmid, msqid, sharedMemPtr);

        /* Go to the main loop */
        mainLoop();

        /** TODO: Detach from shared memory segment, and deallocate shared memory and message queue (i.e. call cleanup) **/

        std::cout<<"Cleaning up"<<std::endl;
        cleanUp(shmid, msqid, sharedMemPtr);
        std::cout<<"Finished"<<std::endl;
        return 0;
}








Upvotes: 0

Views: 171

Answers (0)

Related Questions