Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

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 /* For O_* constants */ #include /* For mode constants */ #include #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 #include #include #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 #include #include "testlib.h"

#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 void test_start(char *filename);

#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

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image_2

Step: 3

blur-text-image_3

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

Expert Oracle9i Database Administration

Authors: Sam R. Alapati

1st Edition

1590590228, 978-1590590225

More Books

Students also viewed these Databases questions

Question

1. What is meant by Latitudes? 2. What is cartography ?

Answered: 1 week ago

Question

What is order of reaction? Explain with example?

Answered: 1 week ago

Question

How do Excel Pivot Tables handle data from non OLAP databases?

Answered: 1 week ago