Last active
August 29, 2015 13:57
-
-
Save AustinW/9865400 to your computer and use it in GitHub Desktop.
CPSC 351 - Assignment 2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CPSC 351 Assignment 2 | |
Authors: Ryan Ott, Ben Hoelzel, Austin White (section 1) | |
Programming language used: C++ | |
Execution: | |
$ make | |
$ ./receiver | |
--- Separate window --- | |
$ ./sender [FILE_NAME] | |
Extra Credit: NO |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
all: receiver sender | |
# Receiver | |
receiver: recv.cpp | |
g++ recv.cpp -o receiver | |
# Sender | |
sender: sender.cpp | |
g++ sender.cpp -o sender |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @File: msg.h | |
* @Description: | |
* | |
* This header file used by both the sender and the receiver. | |
* It contains the struct of the message relayed through message queues. | |
* | |
* @authors: Ryan Ott, Ben Hoelzel, Austin White | |
* @date: March 29th, 2014 | |
*/ | |
// The information type | |
#define SENDER_DATA_TYPE 1 | |
// The done message type | |
#define RECV_DONE_TYPE 2 | |
/** | |
* The message structure | |
* @property long mtype | |
* @property int size | |
*/ | |
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); | |
} | |
// Testing function to print to stdout | |
void printer() | |
{ | |
printf("%d\n", size); | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @File: recv.cpp | |
* @Description: | |
* | |
* This program shall implement the process that receives files from the sender | |
* process. It shall perform the following sequence of steps: | |
* | |
* 1. The program shall be invoked as ./recv where recv is the name of the executable. | |
* 2. The program shall setup a chunk of shared memory and a message queue. | |
* 3. The program shall wait on a message queue to receive a message from the sender | |
* program. When the message is received, the message shall contain a field called | |
* size denoting the number of bytes the sender has saved in the shared memory | |
* chunk. | |
* 4. If size is not 0, then the receiver reads size number of bytes from shared | |
* memory, saves them to the file (always called recvfile), sends message to the | |
* sender acknowl- edging successful reception and saving of data, and finally goes | |
* back to step 3. | |
* 5. Otherwise, if size field is 0, then the program closes the file, detaches the shared | |
* memory, deallocates shared memory and message queues, and exits. | |
* | |
* @authors: Ryan Ott, Ben Hoelzel, Austin White | |
* @date: March 29th, 2014 | |
*/ | |
#include <sys/shm.h> | |
#include <sys/msg.h> | |
#include <signal.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <fstream> | |
#include "msg.h" | |
// The size of the shared memory chunk | |
#define SHARED_MEMORY_CHUNK_SIZE 1000 | |
using namespace std; | |
// 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"; | |
/** | |
* Automatically create a keyfile.txt if it doesn't exist | |
*/ | |
key_t createKeyFile() | |
{ | |
// Open an output filestream | |
ofstream keyFile; | |
// Open the file | |
keyFile.open("keyfile.txt"); | |
// Fill the file with "Hello World" | |
keyFile << "Hello World"; | |
// Close it | |
keyFile.close(); | |
// Try getting the key again using the generated file | |
key_t key = ftok("keyfile.txt", 'a'); | |
// Fail if there's an error | |
if (key < 0) { perror("(ftok) Error opening file"); } | |
return key; | |
} | |
/** | |
* 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) | |
{ | |
key_t key = ftok("keyfile.txt", 'a'); | |
if (key < 0) { | |
key = createKeyFile(); | |
} | |
// Create message queue | |
if ( (shmid = shmget(key, SHARED_MEMORY_CHUNK_SIZE, 0644 | IPC_CREAT)) == -1 ){ | |
perror("shmget"); | |
exit(1); | |
} | |
// Attach to the message queue | |
if ((msqid = msgget(key, 0644 | IPC_CREAT)) == -1) { | |
perror("msgget");//Failed msgget | |
exit(1);//exit | |
} | |
// Attach to the shared memory | |
sharedMemPtr = shmat(shmid, (void *)0, 0); | |
if (sharedMemPtr == (char *)(-1)){ | |
perror("shmat"); | |
exit(1); | |
} | |
} | |
/** | |
* The main loop | |
*/ | |
void mainLoop() | |
{ | |
// The size of the mesage | |
int msgSize; | |
message myMessage; | |
// Open the file for writing | |
FILE* fp = fopen(recvFileName, "w"); | |
// Error checks | |
if ( ! fp) | |
{ | |
perror("Error opening the receiver file"); | |
exit(-1); | |
} | |
/** | |
* ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); | |
* @description: Receive message from the queue | |
* @param msqid: The message queue | |
* @param msgp: Message buffer to send the message to | |
* @param msgsz: Maximum size in bytes for the member mtext of the structure pointed to by the msgp argument | |
* @param msgtyp: If msgtyp is greater than 0, then the first message in the queue of type msgtyp is read | |
* @param msgflag: 0 | IPC_NOWAIT | MSG_EXCEPT | MSG_NOERROR | |
* @return On failure return -1 with errno indicating the error, otherwise msgrcv() returns the number of bytes actually copied into the mtext array. | |
*/ | |
if ( msgrcv(msqid, &myMessage, sizeof(struct message) - sizeof(long), SENDER_DATA_TYPE , 0) == -1) { | |
perror("msgrcv: Error receiving message"); | |
fclose(fp); | |
exit(1); | |
} | |
// Testing for console | |
printf("MsgSize\n"); | |
myMessage.printer(); | |
// Set message size from received message | |
msgSize = myMessage.size; | |
/* 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. | |
* | |
* NOTE: the received file will always be saved into the file called | |
* "recvfile" | |
*/ | |
/* Keep receiving until the sender set the size to 0, indicating that | |
* there is no more data to send | |
*/ | |
while (msgSize != 0) | |
{ | |
// 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) Error writing to file"); | |
} | |
// Set the sent message type | |
myMessage.mtype=RECV_DONE_TYPE; | |
// Send the meassage we are done with message | |
if ( msgsnd(msqid, &myMessage, 0 , 0) == -1) { | |
perror("(msgsnd) Error sending message"); | |
exit(1); | |
} | |
// Receive next message | |
if ( msgrcv(msqid, &myMessage, sizeof(struct message) - sizeof(long), SENDER_DATA_TYPE , 0) == -1) { | |
perror("(msgrcv) Error receiving message"); | |
exit(1); | |
} | |
// Testing for console | |
myMessage.printer(); | |
// Set message size from recived message, LCV | |
msgSize = myMessage.size; | |
} | |
else | |
{ | |
// Close the file | |
fclose(fp); | |
} | |
} | |
} | |
/** | |
* Perfoms the cleanup functions | |
* @param sharedMemPtr - the pointer to the shared memory | |
* @param shmid - the id of the shared memory segment | |
* @param msqid - the id of the message queue | |
*/ | |
void cleanUp(const int& shmid, const int& msqid, void* sharedMemPtr) | |
{ | |
// Detach from shared memory | |
shmdt(sharedMemPtr); // detach shared memory | |
// Deallocate the shared memory chunk | |
shmctl(shmid, IPC_RMID, NULL); // delete shared memory | |
// Deallocate the message queue | |
msgctl(msqid, IPC_RMID, NULL); // deallocate message queue | |
} | |
/** | |
* Handles the exit signal | |
* @param signal - the signal type | |
*/ | |
void ctrlCSignal(int signal) | |
{ | |
// Free system V resources | |
cleanUp(shmid, msqid, sharedMemPtr); | |
} | |
int main(int argc, char** argv) | |
{ | |
/* Install a singnal handler (see signaldemo.cpp sample file). | |
* 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); // signal handler call | |
// Initialize | |
init(shmid, msqid, sharedMemPtr); | |
// Go to the main loop | |
mainLoop(); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @File: sender.cpp | |
* @Description: | |
* | |
* This program shall implement the process that sends files to the receiver process. | |
* It shall perform the following sequence of steps: | |
* | |
* 1. The sender shall be invoked as ./sender file.txt where sender is the name of the | |
* executable and file.txt is the name of the file to transfer. | |
* 2. The program shall then attach to the shared memory segment, and connect to the | |
* message queue both previously set up by the receiver. | |
* 3. Read a predefined number of bytes from the specified file, and store these bytes in | |
* the chunk of shared memory. | |
* 4. Send a message to the receiver (using a message queue). The message shall contain a | |
* field called size indicating how many bytes were read from the file. | |
* 5. Wait on the message queue to receive a message from the receiver confirming success- | |
* ful reception and saving of data to the file by the receiver. | |
* 6. Go back to step 3. Repeat until the whole file has been read. | |
* 7. When the end of the file is reached, send a message to the receiver with the size | |
* field set to 0. This will signal to the receiver that the sender will send no more. | |
* 8. Close the file, detach shared memory, and exit. | |
* | |
* @authors: Ryan Ott, Ben Hoelzel, Austin White | |
* @date: March 29th, 2014 | |
*/ | |
#include <sys/shm.h> | |
#include <sys/msg.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <iostream> | |
#include <fstream> | |
#include "msg.h" | |
// The size of the shared memory chunk | |
#define SHARED_MEMORY_CHUNK_SIZE 1000 | |
// For testing purposes | |
#define MESSAGE_COUNT_FOR_TESTING 1000 | |
using namespace std; | |
// 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) | |
{ | |
//Create file | |
ofstream fout; | |
fout.open("keyfile.txt"); | |
if ( ! fout.good()) { | |
perror("(ofstream) File creation failed"); | |
exit(1); | |
} | |
// Build file bigger than allocated memory chunk. To tests messaging | |
for (int i =0; i < MESSAGE_COUNT_FOR_TESTING; i++){ | |
fout << i << " Hello World!\n"; | |
} | |
fout.close(); | |
// Get key | |
key_t key = ftok("keyfile.txt", 'a'); | |
// Get the id of the shared memory segment | |
if ( (shmid = shmget(key, SHARED_MEMORY_CHUNK_SIZE, 0644 | IPC_CREAT)) == -1 ) { | |
perror("(shmget) Error getting the shared memory segment id"); | |
exit(1); | |
} | |
// Attach to the shared memory | |
sharedMemPtr = shmat(shmid, (void *) 0, 0); | |
if (sharedMemPtr == (char *)(-1)) { | |
perror("(shmat) Error getting a pointer to shared memory"); | |
exit(1); | |
} | |
// Attach to the message queue | |
if ( (msqid = msgget(key, 0644 | IPC_CREAT)) == -1) { | |
perror("(msgget) Error getting message from queue"); | |
exit(1); | |
} | |
} | |
/** | |
* Performs the cleanup functions | |
* @param sharedMemPtr - the pointer to the shared memory | |
* @param shmid - the id of the shared memory segment | |
* @param msqid - the id of the message queue | |
*/ | |
void cleanUp(const int& shmid, const int& msqid, void* sharedMemPtr) | |
{ | |
// Detach from shared memory | |
if (shmdt(sharedMemPtr) == -1) { | |
perror("(shmdt) Error detaching from shared memory"); | |
exit(1); | |
} | |
// Destroy shared memeory | |
if (shmctl(shmid, IPC_RMID, NULL) == -1 ) { | |
perror("(shmctl) Error destroying shared memory"); | |
exit(1); | |
} | |
// Destroy message queue | |
if (msgctl(msqid, IPC_RMID, NULL) == -1) { | |
perror("(msgctl) Error destroying message queue"); | |
exit(1); | |
} | |
} | |
/** | |
* 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"); | |
// Was the file open? | |
if ( ! fp) | |
{ | |
perror("(fopen) Error opening file"); | |
exit(-1); | |
} | |
// A buffer to store message we will send to the receiver. | |
message sndMsg; | |
//Set message type to sender | |
sndMsg.mtype = SENDER_DATA_TYPE; | |
// A buffer to store message received from the receiver. | |
message rcvMsg; | |
/* Read the whole file */ | |
while (!feof(fp)) | |
{ | |
/* Read at most SHARED_MEMORY_CHUNK_SIZE from the file and store them in shared memory. | |
* fread will return how many bytes it has actually read (since the last chunk may be less | |
* than SHARED_MEMORY_CHUNK_SIZE). | |
*/ | |
if ( (sndMsg.size = fread(sharedMemPtr, sizeof(char), SHARED_MEMORY_CHUNK_SIZE, fp)) < 0) { | |
perror("(fread) Error reading from shared memory"); | |
exit(-1); | |
} | |
/* Send message to queue alerting reciver message is ready */ | |
if (msgsnd(msqid, &sndMsg , sizeof(struct message) - sizeof(long), 0) == -1){ | |
perror("(msgsnd) Error sending message to alert receiver"); | |
} | |
/* Wait until the receiver sends a message of type RECV_DONE_TYPE telling the sender | |
* that it finished saving the memory chunk. | |
*/ | |
if ( msgrcv(msqid, &rcvMsg, sizeof(struct message) - sizeof(long), RECV_DONE_TYPE, 0) == -1 ) { | |
perror("(msgrcv) Error receiving message from receiver"); | |
exit(1); | |
} | |
} | |
/* Send message to queue to tell reciver we have no more data to send, size = 0 | |
* Set the message size in sndMsg to 0; siganls no more data | |
*/ | |
sndMsg.size = 0; | |
if (msgsnd(msqid, &sndMsg , sizeof(struct message) - sizeof(long) , 0) == -1) { | |
perror("(msgsnd) Error sending a message"); | |
} | |
// 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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment