Question

This is in C. For this assignment we will write a simple database server. We will...

This is in C.

For this assignment we will write a simple database server.

We will be creating a simple database of student records, so let’s describe these first. The format of a student record is as follows:

typedef struct student {

    char lname[ 10 ], initial, fname[ 10 ];

    unsigned long SID;

    float GPA;

} SREC;

Part One – the Server

We will create a database server. The job of the server is to accept a connection on a socket and perform one of the following actions:

A “get” command asking for the data to be returned in order, either alphabetical order by last name, alphabetical order by first name, in order by student ID, or in order by grade point average. In the case of GPA, the highest should come first (4.0 down to 0.0, not 0.0 up to 4.0).

A “put” command that will take one new SREC and add it to the database.

A “delete” command that will look up a certain SREC by SID and delete that record from the database.

A “stop” command. This command will save the entire database into a file (you name the file whatever you like). When the program starts again, if the file exists the contents are used to initialize the lists. In this way we can insert records, stop the server, run it again, and the records from before are available again. The data should be saved in the file in binary, by using “fread” and “fwrite” or “read” and “write”, whichever you prefer. Each “sizeof(SREC)” represents one student in the file.

While in memory the records must be maintained on four data structures, ordered by “lname”, “fname”, “SID”, or “GPA”. In the case of the names, use the order returned by “strcmp” as the ordering criteria. You can use singly-linked lists, doubly linked lists, or binary search trees – your choice. (If you choose to do search trees, when deleting a record you can mark the tree nodes as deleted and avoid having to write the actual tree code for a delete.)

Part Two – the Client

The client program asks for an activity, and acts on the activity. The client reads commands from the user, formats them into requests to the server, sends the request, and then takes back replies from the server and displays the results. Here are examples of the commands which correspond to the above, along with comments:

Command

Note

get lname

The server sends back the records, ordered by last name

get fname

The server sends back the records, ordered by first name

get SID

The server sends the records back ordered by SID

get GPA

The server sends back the records by high-to-low GPA.

put Mahoney,Bill,R,12345,4.0

The record is added to the database. There are no spaces in the “data” part of the record, and the fields are split apart by commas. The GPA and SID are guaranteed to be valid values, however note that the names may be longer than the 10 characters allowed by the structure. It is up to you to chop the names if necessary.

delete 12345

The database record with SID 12345 is removed.

stop

The server saves the file and exits. The client exits as well.

The format of commands is exactly as shown, in lower case for the commands and in mixed case for the data. “get” is used, not “Get”, for instance, and there will be exactly one space after the command and before any arguments.

The program should correctly handle the case where the user enters a command that is not in the list.

It is necessary to “pretty print” the results that come back from the server. For example, the output should look like this:

Enter next command> get SID

| SID   | Lname    | Fname      | M | GPA |

+-------+-----------+------------+---+------+

| 33445 | Mahoney | Bill       | R | 4.00 |

| 45678 | Cavanaugh | Patrick    | Z | 4.00 |

| 67890 | Dough    | John       | A | 2.67 |

| 88891 | Smythe   | Jane       | F | 3.78 |

| 99341 | Namethati | Waytoolon | S | 3.81 |

+-------+-----------+------------+---+------+

Enter next command> put Simpson,Homer,A,4,1.3

Enter next command> get SID

| SID   | Lname    | Fname      | M | GPA |

+-------+-----------+------------+---+------+

| 00004 | Simpson   | Homer      | A | 1.30 |

| 33445 | Mahoney   | Bill       | R | 4.00 |

| 45678 | Cavanaugh | Patrick    | Z | 4.00 |

| 67890 | Dough     | John       | A | 2.67 |

| 88891 | Smythe    | Jane       | F | 3.78 |

| 99341 | Namethati | Waytoolon | S | 3.81 |

+-------+-----------+------------+---+------+

The output should look exactly as shown (with different data obviously) including the ‘|’, ‘+’, etc. The “SID” should occupy exactly 5 columns, zero filled if needed, with a space on either side. The names, both the last and first, should occupy exactly nine columns, with a space on either side. The middle initial has a space on each side. The GPA should occupy exactly four columns.

Part Three – the Port Number and usage

It will be necessary to make sure that each student in the class has a unique port number to work from. Also, what happens on a Linux machine if a process dies unexpectedly is that the port remains “in use” for a period of time. Thus we will assign port numbers in ranges, with 10 per student. Suppose your port numbers are 20000-20009. You could write the program so that it uses port 20000 and if that port is in use after a program crashes, you can switch to 20001. The ports remain in use only for a certain amount of time, so assigning things in groups of ten should be fine. From playing around on Loki it seems to take about a minute or so before the socket is once again available.

There is a class list posted on Blackboard along with this assignment that shows your port range assignment.

You do not retrieve the port number from a command line argument, rather create an easy to access (and find for my sake) constant for your port number, for example:

#define PORT_NUM 20000

Neither the Server nor the Client should accept any command line arguments. The port number is going to be previously defined on both sides as discussed above, and your client can assume the host as “loki” or “localhost”.

Hints

It will be necessary for the server to “tell” the client how many records will be coming back on a “get” request. I suggest that when the server receives the request, it first sends back an integer to the client, and then the client and server loop, reading (or sending) each record individually.

I would suggest that in the case of a “put”, the client take the command line and convert it into an SREC and then send the “put” command followed by the record.

For that matter, you might consider having the client send an integer or character representing what action is to be taken. These could include the four types of “get” requests as well.

Hand-in instructions…

Note: After the programs are collected, any compiled program (executable) in that directory is deleted and the program is recompiled for testing. Specifically, make sure you compile the program with the same options that are used for grading:

                gcc -Wall –ansi –pedantic –o server server.c

                gcc -Wall –ansi –pedantic –o client client.c

0 0
Add a comment Improve this question Transcribed image text
Answer #1

server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <time.h>

#define FILE_NAME "data"
#define DEBUG 1

/* --- Structures --- */
typedef struct student {
    char lname[10], initial, fname[10];
    unsigned long SID;
    float GPA;
} SREC;

typedef struct node {
    struct node * next;
    SREC * data; /*SREC*/
} Node;

/* --- Function Prototypes --- */
/* IO */
int putRecord(Node * f, Node * l, Node * s, Node * g, const char * cmd, const char * s_gpa, const char * s_sid, const char * first, const char * init, const char * last);
int saveNodes(FILE * fp, Node * start);
void sendRecords(Node * start, int numberOfRecords, int handle);
void readRecords(FILE * fp, Node * first, Node * last, Node * SID, Node * GPA, int * numRec);
void error(char *msg);

/* Nodes */
Node * createNode();
Node * deleteNode(Node *, unsigned long, int *);
Node * insertAtFront(Node * front, SREC * record);
void printNodes(Node * start);
void add(Node * node, SREC * rec);
void swapNodes(Node * alpha, Node * beta);

/* Sorting */
Node * bubbleSortByFirst(Node * top);
Node * bubbleSortByLast(Node * top);
Node * bubbleSortBySID(Node * top);
Node * bubbleSortByGPA(Node * top);
void sortAll(Node * fName, Node * lName, Node * SID, Node * GPA);

/* Utility */
unsigned long getSID(const char * s_SID);
int getTypeID(char * type);
int getCommand(char * cmd);
SREC *newSREC(const char * last, char init, const char * first, unsigned long SID, float GPA);

/* --- Global Static Variables --- */
/* I had to modify some of these from the ones given since some were over the 30 char limit */
static const char *successfulPutResponse = "Record successfully added.";
static const char *unsuccessfulPutResponse = "Error while adding record.";
static const char *unsuccessfulStopResponse = "Error while saving database.";
static const char *successfulStopResponse = "Database saved successfully.";
static const char *successfulDeleteResponse = "Record deleted.";
static const char *unsuccessfulDeleteResponse = "Unable to delete record.";

int main(int argc, char *argv[]){
    int sockfd, newsockfd, portno;
    socklen_t clilen;
    char buffer[256];
    struct sockaddr_in serv_addr, cli_addr;
    int n;
    
    int numRecords = 0;
    int commandID = -1;
    unsigned long tempSID;
    
    /*Linked list node heads for the 4 different sorting types */
    Node * fNameHead = NULL;
    Node * lNameHead = NULL;
    Node * SIDHead = NULL;
    Node * GPAHead = NULL;
    
    FILE * dataFile = NULL;
    
    /* Make sure usage was correct, a port number was provided. */
    if (argc < 2){
        fprintf(stderr,"ERROR, no port provided\n");
        exit(1);
    }
    
    /* Create a socket and make sure socket was successfully opened */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0){
        error("ERROR opening socket");
    }
    
    memset((char *) &serv_addr, 0, sizeof(serv_addr));
    portno = atoi(argv[1]);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
        error("ERROR on binding");
    }
    listen(sockfd,5);
    
    printf("Waiting for client... \n");
    
    clilen = sizeof(cli_addr);
    newsockfd = accept(sockfd, (struct sockaddr * ) & cli_addr, & clilen);
    
    if (newsockfd < 0){
        error("ERROR on accept");
    }
    
    /* Init Nodes */
    fNameHead = createNode();
    lNameHead = createNode();
    SIDHead = createNode();
    GPAHead = createNode();
    
    /* Load data from file */
    dataFile = fopen(FILE_NAME, "r");
    if(dataFile == NULL){
        /*Create it. */
        dataFile = fopen(FILE_NAME, "w+");
        if(dataFile == NULL){
            printf("Unable to create file! \n");
            exit(0);
        } else {
            fclose(dataFile);
        }
    } else {
        readRecords(dataFile, fNameHead, lNameHead, SIDHead, GPAHead, &numRecords);
        sortAll(fNameHead, lNameHead, SIDHead, GPAHead);
        fclose(dataFile);
    }
    /* Main Loop */
    
    printf("Client connected, reading... \n");
    while(1){
        memset(buffer, 0, 256); /*Otherwise we end up with wonkey stuff... */
        n = read(newsockfd,buffer,255);
        if(n<=0){ /*Negative */
            error("ERROR reading from socket");
        }
        
        commandID = getCommand(strtok(buffer, " ")); /*Assuming it's sent as a space! */
        
        if(commandID == 0){ /*Get command */
            n = getTypeID(strtok(NULL, " " )); /*Reuse n */
            if(n == 0){
                sendRecords(fNameHead, numRecords, newsockfd);
            } else if(n ==1){
                sendRecords(lNameHead, numRecords, newsockfd);
            } else if(n == 2){
                sendRecords(SIDHead, numRecords, newsockfd);
            } else if(n == 3){
                sendRecords(GPAHead, numRecords, newsockfd);
            } else {
                sendRecords(NULL, 0, newsockfd); /*No records in that cat...*/
            }
        }
        
        if(commandID == 1){ /*put*/
            if(putRecord(fNameHead, lNameHead, SIDHead, GPAHead,
                         strtok(buffer, ","), strtok(NULL, ","), strtok(NULL, ","),
                         strtok(NULL, ","),strtok(NULL, ","),strtok(NULL, ",")) == 1){
                /*Success!*/
                numRecords++;
                sortAll(fNameHead, lNameHead, SIDHead, GPAHead);
                write(newsockfd, successfulPutResponse, strlen(successfulPutResponse));
            } else {
                write(newsockfd, unsuccessfulPutResponse, strlen(unsuccessfulPutResponse));
            }
        }
        
        if(commandID == 2){ /*delete*/
            tempSID = getSID(strtok(NULL, " ")); /*SID, already toked it to get CommandID*/
            
            /* We're doing assignment since the head node might change...
             In the future might make another field like isDeleted
             that would save a lot of time.
             */
            fNameHead = deleteNode(fNameHead, tempSID, &n);
            lNameHead = deleteNode(lNameHead, tempSID, &n );
            SIDHead = deleteNode(SIDHead, tempSID, &n);
            GPAHead = deleteNode(GPAHead, tempSID, &n);
            
            if(n == 0){ /*Failed*/
                write(newsockfd, unsuccessfulDeleteResponse, strlen(unsuccessfulDeleteResponse));
            } else{
                numRecords--;
                sortAll(fNameHead, lNameHead, SIDHead, GPAHead);
                write(newsockfd, successfulDeleteResponse, strlen(successfulDeleteResponse));
            }
        }
        
        if(commandID == 3){ /*stop*/
            break;
        }
    }
    
    dataFile = fopen(FILE_NAME, "w");
    if(dataFile == NULL){
        printf("Unable to data file. Are you sure it exists? File Name: %s \n", FILE_NAME);
        write(newsockfd, unsuccessfulStopResponse, strlen(unsuccessfulStopResponse));
    } else {
        saveNodes(dataFile, SIDHead);
        fclose(dataFile);
        write(newsockfd, successfulStopResponse, strlen(successfulStopResponse));
    }
    
    close(newsockfd);
    return 0;
}

/* Utility function to print all info starting with a node */
void printNodes(Node * start){
    printf("LN | MI | FM | ID | GPA |\n");
    while(start != NULL && start->data != NULL){
        printf("%s | %c | %s | %lu | %f | \n", start->data->lname, start->data->initial, start->data->fname, start->data->SID, start->data->GPA);
        start = start->next;
    }
    printf("------------------------\n");
}

/* Saves all the nodes under the start node provided.
        Given a file pointer */
int saveNodes(FILE * fp, Node * start){
    while(start != NULL && start->data != NULL){
        fwrite(start->data, sizeof(SREC), 1, fp);
        start = start->next;
    }
    
    return 1;
}

/*Utility function convert from a string to an unsigned long */
unsigned long getSID(const char * s_SID){
    char * temp;  /*strtoul puts the rest of the text in temp after converting */
    return strtoul(s_SID, &temp, 10);
}

/*Sends records to the place specified by the handle. */
void sendRecords(Node * start, int numberOfRecords, int handle){
    int c = 0;
    Node * temp = start;
    
    write(handle, &numberOfRecords, sizeof(int));
    
    if(numberOfRecords == 0){ /*No records to write. */
        return;
    }
    
    while(c < numberOfRecords){
        write(handle, temp->data, sizeof(SREC) );
        temp = temp->next;
        c++;
    }
}

/* Reads records from the given file pointer, passed the 4 node types so we can modify them,
        and numRec to add to. */
void readRecords(FILE * fp, Node * first, Node * last, Node * SID, Node * GPA, int * numRec){
    
    SREC * tempSREC = malloc(sizeof(SREC));
    SREC * cyclingSREC;
    
    while(fread(tempSREC, sizeof(SREC), 1, fp) != 0){ /*Returns 0 when nothing was read */
        /*
         Data is an SREC pointer, so we need to make a new pointer since tempSREC's
         pointed to value is changed. Therefore we need to copy, like you would with strcpy
         */
        cyclingSREC = newSREC(tempSREC->lname, tempSREC->initial, tempSREC->fname, tempSREC->SID, tempSREC->GPA);
        add(first, cyclingSREC);
        add(last, cyclingSREC);
        add(SID, cyclingSREC);
        add(GPA, cyclingSREC);
        
        (*numRec)++;
        free(tempSREC);
        tempSREC = malloc( sizeof(SREC) );
    }
}

/* Creates a Node */
Node * createNode(){
    Node * t;
    t = malloc( sizeof(Node) );
    t->data = NULL;
    t->next = NULL;
    return t;
}

/*strtok calls are called right to left, so SREC is backwards. */
int putRecord(Node * f, Node * l, Node * s, Node * g, const char * cmd, const char * s_gpa, const char * s_sid, const char * init, const char * first, const char * last){
    unsigned long SID;
    float GPA;
    SREC * temp;
    
    if(cmd == NULL || s_gpa == NULL || s_sid == NULL || init == NULL || first == NULL || last == NULL){
        return 0;
    }
    
    
    SID = getSID(s_sid);
    GPA = atof(s_gpa);
    if(SID == 0 || GPA == 0){
        return 0;
    }
    
    temp = newSREC(last, init[0], first, SID, GPA);
    add(f, temp);
    add(l, temp);
    add(s, temp);
    add(g, temp);
    
    return 1;
}

/* Adds Data to a new node appended to the end of the last node */
void add(Node * node, SREC * rec){
    Node * temp;
    temp = node;
    
    /*Head node case. You need data, not another node. */
    if(temp->data == NULL){
        temp->data = rec;
        return;
    }
    
    while(temp->next != NULL){
        temp = temp->next;
    }
    
    temp->next = createNode();
    temp->next->data = rec;
}

Node * deleteNode(Node * head, unsigned long SID, int * result){
    Node * checking;
    
    checking = head;
    if(head->data->SID == SID){
        if(head->next == NULL){
            return createNode();
        }
        return head->next;
    }
    
    while(checking != NULL){
        if(checking->next != NULL){
            if(checking->next->data->SID == SID){ /*Delete it. */
                if(checking->next->next != NULL){ /*Is there one after the one we found? */
                    checking->next = checking->next->next;
                    (*result) = 1;
                    return head;
                } else { /*The last element is the one... */
                    checking->next = NULL;
                    (*result) = 1;
                    return head;
                }
            }
        }
        checking = checking->next;
    }
    
    (*result) = 0;
    return head; /*Nothing was there to delete...*/
}

void sortAll(Node * fName, Node * lName, Node * SID, Node * GPA){
    bubbleSortByFirst(fName);
    bubbleSortByLast(lName);
    bubbleSortBySID(SID);
    bubbleSortByGPA(GPA);
}

/* Inserts a new node at the FRONT. Choose to return
 rather than dealing with pointers to pointers...
 Currently not used.
 */
Node * insertAtFront(Node * front, SREC * record){
    Node * newNode = createNode();
    
    newNode->data = record;
    newNode->next = front;
    
    return newNode;
}

/*Swaps the data in the nodes, rather than the pointers. */
void swapNodes(Node * alpha, Node * beta){
    SREC * tempRecord = alpha->data;
    alpha->data = beta->data;
    beta->data = tempRecord;
}

SREC *newSREC(const char * last, char init, const char * first, unsigned long SID, float GPA){
    SREC * temp = malloc(sizeof(SREC));
    
    /* They're arrays they don't need mallocing*/
    strncpy(temp->lname, last, 9);
    
    /* They're arrays, we good.*/
    strncpy(temp->fname, first, 9);
    
    /* Addition made by OM. Initial wasn't initialized */
    temp->initial = init;
    
    temp->SID = SID;
    
    temp->GPA = GPA;
    
    return temp;
    
}

/* Utility that takes a string and identifies what command ID it is. */
int getCommand(char * cmd){
    if(strcmp(cmd, "get") == 0){
        return 0;
    }
    
    if(strcmp(cmd, "put") == 0){
        return 1;
    }
    
    if(strcmp(cmd, "delete") == 0){
        return 2;
    }
    
    if(strcmp(cmd, "stop") == 0){
        return 3;
    }
    
    return -1;
}

/*Takes a type string and converts it to an id.
        Types are the fname, lname, SID, GPA  from get commands*/
int getTypeID(char * type){
    if(type == NULL){
        return -1;
    }
    
    if(strcmp(type, "fname") == 0){
        return 0;
    }
    
    if(strcmp(type, "lname") == 0){
        return 1;
    }
    
    if(strcmp(type, "SID") == 0){
        return 2;
    }
    
    if(strcmp(type, "GPA") == 0){
        return 3;
    }
    
    return -1;
}

Node * bubbleSortByFirst(Node * top){
    int hasSwapped;
    int strcmpResult;
    
    Node * alpha;
    
    /* Nothing needs sorting. Only have one thing. */
    if(top->next == NULL){
        return top;
    }
    
    do{
        hasSwapped = 0; /*FALSE*/
        alpha = top;
        
        while(alpha->next != NULL){ /*While we have something to possibly swap... */
            strcmpResult = strcmp(alpha->data->fname, alpha->next->data->fname);
            
            if(strcmpResult > 0){
                swapNodes(alpha, alpha->next);
                hasSwapped = 1; /*Aye! We swapped. Gotta go again! */
            }
            
            alpha = alpha->next;
        }
        
    }while(hasSwapped);
    
    /* The data has changed. Not the actual pointer it self. */
    return top;
}

Node * bubbleSortByLast(Node * top){
    int hasSwapped;
    int strcmpResult;
    
    Node * alpha;
    
    /* Nothing needs sorting. Only have one thing. */
    if(top->next == NULL){
        return top;
    }
    
    do{
        hasSwapped = 0; /*FALSE*/
        alpha = top;
        
        while(alpha->next != NULL){ /*While we have something to possibly swap... */
            strcmpResult = strcmp(alpha->data->lname, alpha->next->data->lname);
            
            if(strcmpResult > 0){
                swapNodes(alpha, alpha->next);
                hasSwapped = 1; /*Aye! We swapped. Gotta go again! */
            }
            
            alpha = alpha->next;
        }
        
    }while(hasSwapped);
    
    /* The data has changed. Not the actual pointer it self. */
    return top;
}

Node * bubbleSortBySID(Node * top){
    int hasSwapped;
    
    Node * alpha;
    
    /* Nothing needs sorting. Only have one thing. */
    if(top->next == NULL){
        return top;
    }
    
    do{
        hasSwapped = 0; /*FALSE*/
        alpha = top;
        
        while(alpha->next != NULL){ /*While we have something to possibly swap... */
            
            if(alpha->data->SID > alpha->next->data->SID){
                swapNodes(alpha, alpha->next);
                hasSwapped = 1; /*Aye! We swapped. Gotta go again! */
            }
            
            alpha = alpha->next;
        }
        
    }while(hasSwapped);
    
    /* The data has changed. Not the actual pointer it self. */
    return top;
}

Node * bubbleSortByGPA(Node * top){
    int hasSwapped;
    
    Node * alpha;
    
    /* Nothing needs sorting. Only have one thing. */
    if(top->next == NULL){
        return top;
    }
    
    do{
        hasSwapped = 0; /*FALSE*/
        alpha = top;
        
        while(alpha->next != NULL){ /*While we have something to possibly swap... */
            
            if(alpha->data->GPA < alpha->next->data->GPA){
                swapNodes(alpha, alpha->next);
                hasSwapped = 1; /*Aye! We swapped. Gotta go again! */ 
            }
            
            alpha = alpha->next; 
        }
        
    }while(hasSwapped); 
    
    /* The data has changed. Not the actual pointer it self. */ 
    return top; 
}

void error(char * msg){
    printf("%s\n", msg); 
    exit(0); 
}

======================================================================

client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <ctype.h>

#define SERVER_COMMAND_EXECUTION_RESPONSE_LENGTH 30

static const char * GetCommand = "get";
static const char * PutCommand = "put";
static const char * DeleteCommand = "delete";
static const char * StopCommand = "stop";
static const char * StudentIdTitle = "SID";
static const char * LastNameTitle = "Lname";
static const char * FirstNameTitle = "Fname";
static const char * MiddleInitialTitle = "M";
static const char * GPA_Title = "GPA";
static const char * RecordHeaderPrintFormat = "| %-5s | %-9s | %-9s | %s | %-4s |\n";
static const char * RecordBorderPrintFormat = "+-------+-----------+-----------+---+------+";
static const char * RecordDataPrintFormat = "| %05lu | %-9s | %-9s | %c | %1.2f |\n";

typedef struct student {
    char lname[10], initial, fname[10];
    unsigned long SID;
    float GPA;
} SREC;

enum COMMAND {
    Invalid, Get, Put, Delete, Stop
};

typedef enum COMMAND Command;

Command getCommand(const char *command);
void error(char *msg);
void startDatabaseSession(int sockfd);
void removeTrailingWhitespace(char *buffer);
void handleGetCommandResponse(int sockfd);
void printStudentRecords(SREC *studentRecords, int numberOfRecords);
void handleResponse(int sockfd, Command command);
void handleDeleteCommandResponse(int sockfd);
void handleStopCommandResponse(int sockfd);
void handlePutCommandResponse(int sockfd);
void printServerResponse(int sockfd);




int main(int argc, char *argv[])
{
    int sockfd, portno;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    
    if (argc < 3){
        fprintf(stderr,"usage %s hostname port\n", argv[0]);
        exit(0);
    }
    portno = atoi(argv[2]);
    sockfd = socket (AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0){ error("ERROR opening socket");}
    server = gethostbyname(argv[1]);
    if (server == NULL){
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }
    
    memset((char *) &serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    memcpy((char *)server->h_addr_list, (char*)&serv_addr.sin_addr.s_addr, server->h_length);
    serv_addr.sin_port = htons(portno);
    
    if (connect(sockfd,(struct sockaddr*) &serv_addr,sizeof(serv_addr)) < 0){
        error("ERROR connecting");
    }
    
    startDatabaseSession(sockfd);
    
    close(sockfd);
    
    return 0;
} /* end of main */

/* Start issuing commands to database */
/* input "stop" to end database session */
/* returns void */
void startDatabaseSession(int sockfd)
{
    char commandBuffer[100];
    Command command;
    ssize_t n;

    do {
        printf("Enter next command> ");
        memset(commandBuffer, 0, 100);
        fgets(commandBuffer, 256, stdin);
        removeTrailingWhitespace(commandBuffer);
        command = getCommand(commandBuffer);
        
        if (command == Invalid) {
            printf("Command entered not valid.\n");
            /* printUsage(); */
            continue;
        }
        
        n = write(sockfd, commandBuffer, strlen(commandBuffer));
        if (n < 0){
            error("ERROR writing to socket");
        }
        
        handleResponse(sockfd, command);
    
    } while ( command != Stop);
    
    return;
} /* end of startDatabaseSession */


/* handles response from server after issuing command */
/* returns void */
void handleResponse(int sockfd, Command command)
{
    switch (command) {
        case Invalid:
            puts("Invalid command should not have been sent to client");
            exit(1);
            
        case Get:
            handleGetCommandResponse(sockfd);
            return;
            
        case Put:
        case Delete:
        case Stop:
            printServerResponse(sockfd);
            return;
            
        default:
            puts("Invalid command was passed to handleResponse function.");
            exit(1);
    }
} /* end of handleResponse */

/* Used to handle reponse from server after issuing 
 * a put, delete, or stop command
 * return void
 */
void printServerResponse(int sockfd)
{
    char buffer[30];
    memset(buffer, '\0', 30);
    
    read(sockfd, buffer, 30);
    puts(buffer);
    
    return;
} /* end of printServerResponseFunction */

/* Handles response from server after client issued a get command */
/* returns void */
void handleGetCommandResponse(int sockfd)
{
    ssize_t n;
    int numberOfRecords = -1;
    SREC *studentRecords = NULL;
    int index;
    
    /* Read number of records to be read */
    n = read(sockfd, &numberOfRecords, sizeof(int));
    if (n < 0){
        error("ERROR writing to socket");
    }
    
    /* If number of records read is 0 */
    if (!numberOfRecords) {
        printStudentRecords(NULL, numberOfRecords);
        return;
    }
    
    /* Allocate array of student records */
    studentRecords = malloc(sizeof(SREC) * numberOfRecords);
    
    /* Read in record data into struct */
    for (index = 0; index < numberOfRecords; index++)
    {
        n = read(sockfd, &studentRecords[index], sizeof(SREC));
        if (n < 0) {
            error("ERROR reading from socket");
        }
    }
    
    printStudentRecords(studentRecords, numberOfRecords);
} /* end of handleGetCommandResponse */


/* prints student records in appropriate format to stdout */
/* returns void */
void printStudentRecords(SREC *studentRecords, int numberOfRecords)
{
    int index;
    
    printf(RecordHeaderPrintFormat, StudentIdTitle, LastNameTitle, FirstNameTitle, MiddleInitialTitle, GPA_Title);
    puts(RecordBorderPrintFormat);
    
    for (index = 0; index < numberOfRecords; index++) {
        printf(RecordDataPrintFormat, studentRecords[index].SID, studentRecords[index].lname, studentRecords[index].fname, studentRecords[index].initial, studentRecords[index].GPA);
    }
    
    puts(RecordBorderPrintFormat);
    
} /* end of printStudentRecords */


/* return what kind of command the string command issues */
/* returns Command */
Command getCommand(const char *fullCommand)
{
    char *token = NULL;
    char *copy = NULL;
    
    copy = malloc(strlen(fullCommand) + 1);
    strcpy(copy, fullCommand);
    
    /* get command from fullCommand */
    token = strtok(copy, " ");
    
    /* return type of command issued */
    if (!strcmp(token, GetCommand))
    {
        /* Check if arg passed to get is valid */
        token = strtok(NULL, " ");
        
        /* if token NULL */
        if ( !token ) {
            return Invalid;
        }
        
        if (!strcmp(token, "lname"));
        else if (!strcmp(token, "fname"));
        else if (!strcmp(token, "SID"));
        else if (!strcmp(token, "GPA"));
        else
        {
            return Invalid;
        }
        
        free(copy);
        copy = NULL;
        
        return Get;
    }
    else if (!strcmp(token, PutCommand))
    {
        return Put;
    }
    else if (!strcmp(token, DeleteCommand))
    {
        return Delete;
    }
    else if (!strcmp(token, StopCommand))
    {
        return Stop;
    }
    else {
        return Invalid;
    }
} /* end of getCommand */


/* Note: Not sure if we need this yet. */
void removeTrailingWhitespace(char *buffer)
{
    ssize_t length = strlen(buffer);
    while (length - 1 >= 0 && isspace(buffer[length -1])) {
        buffer[length - 1] = '\0';
        length--;
    }
    
    return;
}


void error(char *msg) {
    perror(msg);
    exit(0);
}

=============================================================================

student.h

#ifndef student_h
#define student_h

typedef struct student {
    char lname[10], initial, fname[10];
    unsigned long SID;
    float GPA;
} SREC;

#endif /* student_h */

========================================================================

Add a comment
Know the answer?
Add Answer to:
This is in C. For this assignment we will write a simple database server. We will...
Your Answer:

Post as a guest

Your Name:

What's your source?

Earn Coins

Coins can be redeemed for fabulous gifts.

Not the answer you're looking for? Ask your own homework help question. Our experts will answer your question WITHIN MINUTES for Free.
Similar Homework Help Questions
  • Here is the description of the client and server programs that you need to develop in C using TCP: Suppose we have a simple student query system, where the server keeps student's info in an array...

    Here is the description of the client and server programs that you need to develop in C using TCP: Suppose we have a simple student query system, where the server keeps student's info in an array of struct student_info ( char abc123171 char name [101 double GPA; To simplify the tasks, the server should create a static array of 10 students with random abc123, name, and GPA in the server program. Then the server waits for clients. When a client...

  • Using network sockets, write a C program called client that receives three command-line arguments in the...

    Using network sockets, write a C program called client that receives three command-line arguments in the form: client host port file and sends a request to a web server. The command-line arguments are hostRepresents the web server to connect to port Represents the port number where a request is sent. Normally an HTTP request is sent over port 80, but this format allows for custom ports file Represents the file requested from the web server Your program should create a...

  • Project Description In this project, you will be developing a multithreaded Web server and a simple...

    Project Description In this project, you will be developing a multithreaded Web server and a simple web client. The Web server and Web client communicate using a text-based protocol called HTTP (Hypertext Transfer Protocol). Requirements for the Web server The server is able to handle multiple requests concurrently. This means the implementation is multithreaded. In the main thread, the server listens to a specified port, e.g., 8080. Upon receiving an HTTP request, the server sets up a TCP connection to...

  • Assignment One program will be the update server and the other will be the update client....

    Assignment One program will be the update server and the other will be the update client. Here is how the two programs should interact with each other: Server 1. the server starts up and reads the version number in the data.bin file and stores it in memory. 2. The server binds to a port and awaits connections. Client 1. The client starts up and it will first read the version number found within it's own data.bin file. 2. The client...

  • You must first compile both .cs file into .exe. Then, run the server in one command...

    You must first compile both .cs file into .exe. Then, run the server in one command prompt window and run two cilents, each in a separate command prompt window. To quit a client, you may enter no book title but just hit the enter or enter Ctrl-C. The server always displays a message whenever a client is connected and disconnected. <?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key = "U101" value="PHYSICS"/> <add key = "U102" value="EDU"/> <add key = "U103"...

  • i need help with this python assignment asking for creating a simple database (client application )...

    i need help with this python assignment asking for creating a simple database (client application ) そ归乔 Assignment rh ENCS-393-2174-WW: Tset5.pdf A2.pdf textbook.pdf Department of ComputV ← → O仚 file:///C 18/comp%20348/A2.pdf 5. Print Report: This will print the contents of the database, sorted by name. Note that the sorted contents should be sent by the server back to the client and then displayed by the client app. The Print Report function is r because it is the primary way for...

  • Hello all, I have a c++/unix (bash) question. I am struggling on starting this assignment. If...

    Hello all, I have a c++/unix (bash) question. I am struggling on starting this assignment. If you could start the assignment and tell me how to do the rest it would be greatly appreciated! (Quick thumbs up answer response if thorough and correct) Maintain automobile records in a database Write a shell script to create, view and modify a simple database that contains automobile records. The shell script has to be done in Bourne shell syntax (bash as a matter...

  • Write two programs Client and Server

    Given two integer matrices A and B, you are requested to compose a program to perform matrix addition (A + B). Both matrices have N rows and M columns; N > 1, M > 1; You need to divide both (A and B) into four equal (or close to equal) size of submatrices (A0,0, A0,1, A1,0, A1,1 and B0,0, B0,1, B1.0, B1.1)andeachsubmatrixhasdimensioncloseto(N/2)x(M/2). YouneedtocreatefourJavathreads each thread performs a subset of addition on one pair of the submatrices. Example, thread 0 performs addition...

  • Using python 3 to create the UDP Ping Clien and server. Using UDP sockets, you will...

    Using python 3 to create the UDP Ping Clien and server. Using UDP sockets, you will write a client and server program that enables the client to determine the round-trip time (RTT) to the server. To determine the RTT delay, the client records the time on sending a ping request to the server, and then records the time on receiving a ping response from the server. The difference in the two times is the RTT. The ping message contains 2...

  • You are to write a Java program using the following instructions to build a bank-ATM server...

    You are to write a Java program using the following instructions to build a bank-ATM server system with sockets. A bank holds accounts that can have deposits, withdrawals, or retrievals of balance. The bank server provides the account for transactions when a client uses and ATM machine. The ATM asks for the type of transaction and the amount (if needed), then creates a socket connection to the bank to send the transaction for processing. The bank performs the transaction on...

ADVERTISEMENT
Free Homework Help App
Download From Google Play
Scan Your Homework
to Get Instant Free Answers
Need Online Homework Help?
Ask a Question
Get Answers For Free
Most questions answered within 3 hours.
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT