Question
Program in C and just edit message_queue.c In this question you will write a simple client-/server application using two processes and a mailbox (known as
Program in C and just edit message_queue.c
In this question you will write a simple client-/server application using two processes and a mailbox (known as message queue in Linux) for communication. The server ac- cepts commands from the client and performs corresponding actions. The message format is defined in the template by the Message structure, the available commands are defined in the Command enumeration.
Implement the server in the runServer function. The server should adhere to the following criteria: Returns -1 on any error, 0 otherwise. Creates and initializes a new message queue, which takes Message structures and provides space for 10 messages, using the mq open call and appropriate flags for read-only access and QUEUE NAME as name. Fails if the message queue already exists. Receives messages from the client and processes them until an exit condition is met. The template already contains an implementation of the following commands: CmdExit Exits the server CmdAdd Adds the two parameters supplied in the message and prints the result with the FORMAT STRING ADD format string. CmdSubtract Subtracts the second message parameter from the first one and prints the result with the FORMAT STRING SUBTRACT format string. Exists on error or on reception of an unknown command. Closes the message queue on exit and unlinks it int runServer(); Implement the client functions. Assume the message queue to be already created by the server and ready to be opened for write access by the client.
mqd_t startClient(); int sendExitTask(mqd_t client); int sendAddTask(mqd_t client, int operand1, int operand2); int sendSubtractTask(mqd_t client, int operand1, int operand2); int stopClient(mqd_t client);
The file message_queue.c file:
#include "message_queue.h" #include
/* * The commands supported by the server */ typedef enum _Command { CmdAdd = 0x00, // Adds the two message parameters CmdSubtract, // Subtracts the two message parameters CmdExit // Stops the server } Command;
/* * The message format to be sent to the server. */ typedef struct _Message { /* * One of the command constants. */ Command command; /* * Used as operand 1 (if required) */ int parameter1; /* * Used as operand 2 (if required) */ int parameter2; } Message;
#define QUEUE_NAME "/simple_calculator"
#define FORMAT_STRING_ADD "Calc: %d + %d = %d " #define FORMAT_STRING_SUBTRACT "Calc: %d - %d = %d "
mqd_t startClient(void) { // TODO: Open the message queue previously created by the server return -1;}
int sendExitTask(mqd_t client) { (void)client;
// TODO: Send the exit command to the server. return -1; }
int sendAddTask(mqd_t client, int operand1, int operand2) { (void)client; (void)operand1; (void)operand2;
// TODO: Send the add command with the operands return -1; }
int sendSubtractTask(mqd_t client, int operand1, int operand2) { (void)client; (void)operand1; (void)operand2;
// TODO: Send the sub command with the operands return -1; }
int stopClient(mqd_t client) { (void)client;
// TODO: Clean up anything on the client-side return -1;
}
int runServer(void) { int didExit = 0, hadError = 0; Message msg;
struct mq_attr attr; attr.mq_flags = 0; attr.mq_maxmsg = 10; // Maximum number of messages in the queue attr.mq_msgsize = sizeof(msg); // Maximum message size attr.mq_curmsgs = 0; (void) attr;
// TODO: // Create and open the message queue. Server only needs to read from it. // Clients only need to write to it, allow for all users. mqd_t server = -1; if(server == -1) { return -1; }
// This is the implementation of the server part, already completed: // TODO: You may have to make minor extensions in order to satisfy all requirements do { // Attempt to receive a message from the queue. ssize_t received = mq_receive(server, (char*)&msg, sizeof(msg), NULL); if (received != sizeof(msg)) { // This implicitly also checks for error (i.e., -1) hadError = 1; continue; }
switch (msg.command) { case CmdExit: // End this loop. didExit = 1; break;
case CmdAdd: // Print the required output. printf(FORMAT_STRING_ADD, msg.parameter1, msg.parameter2, msg.parameter1 + msg.parameter2); break;
case CmdSubtract: // Print the required output. printf(FORMAT_STRING_SUBTRACT, msg.parameter1, msg.parameter2, msg.parameter1 - msg.parameter2); break;
default: break; } } while (!didExit);
// TODO // Close the message queue on exit and unlink it
return hadError ? -1 : 0; }
The main is used just to test message_queue.c
The main file:
#include "testlib.h" #include "message_queue.h" #include
int main() { // This is just in case you missed to clean up the queue. // If your program works correctly, this line should not be needed. mq_unlink("/simple_calculator");
switch(fork()) { case -1: perror("fork"); exit(0); case 0: // Child is server printf("Starting test server "); if (runServer() < 0) { perror("runServer"); exit(1); } printf("Test server done "); break; default: // Hope that the server is started now. sleep(1); // Send some test commands to server. printf("Running test client "); mqd_t clientHandle = startClient(); if (clientHandle < 0) { perror("startClient"); exit(1); } if (sendAddTask(clientHandle, 10, -2) < 0) { perror("sendAddTask"); } if (sendSubtractTask(clientHandle, 5, 13) < 0) { perror("sendSubtractTask"); } if (sendExitTask(clientHandle) < 0) { perror("sendExitTask"); } if (stopClient(clientHandle) < 0) { perror("stopClient"); } printf("Test client done "); wait(NULL); }
return 0; }
The Makefile:
CC= gcc LD= ld CFLAGS= -g -W -Wall -Werror -std=c99 -lrt TARGET= message_queue SRC= message_queue.c testlib.c main.c OBJ= $(SRC:.c=.o)
message_queue: $(OBJ) $(CC) -o $@ $(OBJ) -lrt
.PHONY: $(TARGET)-solution.o $(TARGET)-sol: $(subst $(TARGET),$(TARGET)-solution,$(OBJ)) $(CC) -o $@ $^ -lrt
$(TARGET)-solution.o: @test -f $(TARGET)-solution.c \ || { echo "Please download solution." >&2; false; } $(CC) $(CFLAGS) -c $(TARGET)-solution.c
%.o: %.c $(CC) $(CFLAGS) -c $<
clean: rm -rf $(TARGET) $(TARGET)-sol *.o
The message_queue.h file:
#ifndef MESSAGE_QUEUE_H #define MESSAGE_QUEUE_H
#include
mqd_t startClient(void);
int sendExitTask(mqd_t client);
int sendAddTask(mqd_t client, int operand1, int operand2);
int sendSubtractTask(mqd_t client, int operand1, int operand2);
int stopClient(mqd_t client);
int runServer(void);
#endif
The file testlib.c:
#include
#define test_failed_expected(type, should, is, file, line) { \ printf("%s line %d: Expected " type ", but got " type " ", file, line, should, is); \ had_error = 1; }
int had_error = 0;
void _test_failed_message(char *message, char *file, int line) { printf("%s line %d: %s ", file, line, message); }
void test_start(char *filename) { printf("Starting to test %s... ", filename); }
void _test_equals_int64(int64_t is, int64_t should, char* file, int line) { if (is != should) { test_failed_expected("%"PRIu64, should, is, file, line); } }
void _test_equals_int(int is, int should, char* file, int line) { if (is != should) { test_failed_expected("%d", should, is, file, line); } }
void _test_failed() { had_error = 1; }
void _test_equals_string(char* is, char* should, char* file, int line) { if (strcmp(is, should) != 0) { test_failed_expected("\"%s\"", should, is, file, line); } }
int test_end() { if (had_error) { printf("You have errors in your solution, please fix them. "); } else { printf("All test cases passed. This does not mean your solution is correct. "); } return had_error; }
The testlib.h file:
#ifndef TESTLIB_H #define TESTLIB_H
#include
#define test_equals_int(is, should) _test_equals_int(is, should, __FILE__, __LINE__); void _test_equals_int(int is, int should, char* file, int line);
#define test_equals_int64(is, should) _test_equals_int64(is, should, __FILE__, __LINE__); void _test_equals_int64(int64_t is, int64_t should, char* file, int line);
#define test_equals_string(is, should) _test_equals_string(is, should, __FILE__, __LINE__); void _test_equals_string(char* is, char* should, char* file, int line);
#define test_failed_message(message) _test_failed_message(message, __FILE__, __LINE__); void _test_failed_message(char *message, char *file, int line);
int test_end();
#endif
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started