Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

Overview: Write server that is able to: Send a listing of the files in a directory to the client Write file give to it by

Overview: Write server that is able to:

Send a listing of the files in a directory to the client Write file give to it by the client Spellcheck a file the client gave it Delete a file Sample output: Client: Server: $ ./wordClient Machine name [localhost]? (I just press enter to use localhost as the default) Port number? 2000 What would you like to do: (1) List files (2) Write file (3) Spell check a file (4) Delete a file (0) Quit Your choice? 1 Sending "l" . ..

What would you like to do: (1) List files (2) Write file (3) Spell check a file (4) Delete a file (0) Quit Your choice? 2 Text? Hello Muddah, hello Faddah, Here I am at Camp Grenada. Camp is very ent ertaining, And they say we'll have some fun if it stops raining. I went hiking w ith Joe Spivey, He developed poison ivy. You remember Leonard Skinner, He got Pt omaine poisoning last night after dinner. File number (0-63)? 0 Sending "w 0 "Hello Muddah, hello Faddah, Here I am at Camp Grenada. Camp is ve ry entertaining, And they say we'll have some fun if it stops raining. I went hi king with Joe Spivey, He developed poison ivy. You remember Leonard Skinner, He got Ptomaine poisoning last night after dinner. "" Okay What would you like to do: (1) List files (2) Write file (3) Spell check a file (4) Delete a file (0) Quit Your choice? 1 Sending "l" . .. 0.txt

What would you like to do: (1) List files (2) Write file (3) Spell check a file (4) Delete a file (0) Quit Your choice? 3 File number (0-63)? 1 Sending "s 1" Error doing operation

What would you like to do: (1) List files (2) Write file (3) Spell check a file (4) Delete a file (0) Quit Your choice? 3 File number (0-63)? 0 Sending "s 0" Muddah Faddah Spivey

What would you like to do: (1) List files (2) Write file (3) Spell check a file (4) Delete a file (0) Quit Your choice? 1 Sending "l" . .. 0.txt

What would you like to do: (1) List files (2) Write file (3) Spell check a file (4) Delete a file (0) Quit Your choice? 4 File number (0-63)? 1 Sending "d 1" Error doing operation What would you like to do: (1) List files (2) Write file (3) Spell check a file (4) Delete a file (0) Quit Your choice? 1 Sending "l" . .. 0.txt

What would you like to do: (1) List files (2) Write file (3) Spell check a file (4) Delete a file (0) Quit Your choice? 4 File number (0-63)? 0 Sending "d 0" Okay What would you like to do: (1) List files (2) Write file (3) Spell check a file (4) Delete a file (0) Quit Your choice? 1 Sending "l" . ..

What would you like to do: (1) List files (2) Write file (3) Spell check a file (4) Delete a file (0) Quit Your choice? 0 Sending "q" Good bye!

(I ran the server in a subdirectory of where the client and server were) $ ../wordServer Port number to monopolize? 2000 Thread 0 starting.

Thread 0 received: l

Thread 0 received: w 0 "Hello Muddah, hello Faddah, Here I am at Camp Grenada. Camp is very entertaining, And they say we'll have some fun if it stops raining. I went hiking with Joe Spivey, He developed poison ivy. You remember Leonard Sk inner, He got Ptomaine poisoning last night after dinner. "

Thread 0 received: l

Thread 0 received: s 1

Thread 0 received: s 0

Thread 0 received: l

Thread 0 received: d 1

Thread 0 received: l

Thread 0 received: d 0

Thread 0 received: l

Thread 0 received: q Thread 0 quitting. (That thread has ended, but the server is still running) Assignment: Copy and paste the following 3 files: /*-------------------------------------------------------------------------* *--- ---* *--- wordClientServer.h ---* *--- ---* *--- This file declares C functions and constants common to both ---* *--- wordClient.c and wordServer.c. ---* *--- ---* *--- ---- ---- ---- ---- ---- ---- ---- ---- ---* *--- ---* *--- Version 1a Joseph Phillips ---* *--- ---* *-------------------------------------------------------------------------*/

//--- Header file inclusion ---//

#include #include #include #include // For unlink() #include // For waitpid(), opendir() #include // For waitpid() #include // For opendir(), readdir(), closedir() #include // For socket() #include // For sockaddr_in and htons() #include // For getaddrinfo() #include // For errno var #include // For open(), read(),write(), stat() #include // and close()

//--- Definition of constants: ---//

#define BUFFER_LEN 512

#define DIR_CMD_CHAR 'l'

#define WRITE_CMD_CHAR 'w'

#define SPELL_CMD_CHAR 's'

#define DELETE_CMD_CHAR 'd'

#define QUIT_CMD_CHAR 'q'

const int MIN_FILE_NUM = 0;

const int MAX_FILE_NUM = 63;

#define SPELLER_PROGNAME "/usr/bin/aspell"

#define SPELLER_PROG_OPTION "list"

#define ENDING_TEXT "xxxyyyzzz"

#define FILENAME_EXTENSION ".txt" /*-------------------------------------------------------------------------* *--- ---* *--- wordClient.c ---* *--- ---* *--- This file defines a C program that gets file-sys commands ---* *--- from the user, and sends them to a server via a socket, waits ---* *--- for a reply, and outputs the response to the user. ---* *--- ---* *--- ---- ---- ---- ---- ---- ---- ---- ---- ---* *--- ---* *--- Version 1a Joseph Phillips ---* *--- ---* *-------------------------------------------------------------------------*/

// Compile with: // $ gcc wordClient.c -o wordClient

//--- Header file inclusion ---//

#include "wordClientServer.h"

//--- Definition of constants: ---//

#define DEFAULT_HOSTNAME "localhost"

//--- Definition of functions: ---//

// PURPOSE: To ask the user for the name and the port of the server. The // server name is returned in 'url' up to length 'urlLen'. The port // number is returned in '*portPtr'. No return value. void obtainUrlAndPort (int urlLen, char* url, int* portPtr ) { // I. Application validity check: if ( (url == NULL) || (portPtr == NULL) ) { fprintf(stderr,"BUG: NULL ptr to obtainUrlAndPort() "); exit(EXIT_FAILURE); }

if (urlLen <= 1) { fprintf(stderr,"BUG: Bad string length to obtainUrlAndPort() "); exit(EXIT_FAILURE); }

// II. Get server name and port number: // II.A. Get server name: printf("Machine name [%s]? ",DEFAULT_HOSTNAME); fgets(url,urlLen,stdin);

char* cPtr = strchr(url,' ');

if (cPtr != NULL) *cPtr = '\0';

if (url[0] == '\0') strncpy(url,DEFAULT_HOSTNAME,urlLen);

// II.B. Get port numbe: char buffer[BUFFER_LEN];

printf("Port number? "); fgets(buffer,BUFFER_LEN,stdin);

*portPtr = strtol(buffer,NULL,10);

// III. Finished: }

// PURPOSE: To attempt to connect to the server named 'url' at port 'port'. // Returns file-descriptor of socket if successful, or '-1' otherwise. int attemptToConnectToServer (const char* url, int port ) { // I. Application validity check: if (url == NULL) { fprintf(stderr,"BUG: NULL ptr to attemptToConnectToServer() "); exit(EXIT_FAILURE); }

// II. Attempt to connect to server: // II.A. Create socket: int socketDescriptor = socket(AF_INET, // AF_INET domain SOCK_STREAM, // Reliable TCP 0);

// II.B. Ask DNS about 'url': struct addrinfo* hostPtr; int status = getaddrinfo(url,NULL,NULL,&hostPtr);

if (status != 0) { fprintf(stderr,gai_strerror(status)); return(-1); }

// II.C. Attempt to connect to server: struct sockaddr_in server; // Clear server datastruct memset(&server, 0, sizeof(server));

// Use TCP/IP server.sin_family = AF_INET;

// Tell port # in proper network byte order server.sin_port = htons(port);

// Copy connectivity info from info on server ("hostPtr") server.sin_addr.s_addr = ((struct sockaddr_in*)hostPtr->ai_addr)->sin_addr.s_addr;

status = connect(socketDescriptor,(struct sockaddr*)&server,sizeof(server));

if (status < 0) { fprintf(stderr,"Could not connect %s:%d ",url,port); return(-1); }

// III. Finished: return(socketDescriptor); }

// PURPOSE: To ask the user for a file number, and to return that number. // No parameters. int getFileNumber () { // I. Application validity check:

// II. Get number: char buffer[BUFFER_LEN]; int choice;

do { printf(" File number (%d-%d)? ",MIN_FILE_NUM,MAX_FILE_NUM); fgets(buffer,BUFFER_LEN,stdin); choice = strtol(buffer,NULL,10); } while ( (choice < MIN_FILE_NUM) || (choice > MAX_FILE_NUM) );

// III. Finished: return(choice); }

// PURPOSE: To const char* getText () { // I. Application validity check:

// II. : static char buffer[BUFFER_LEN-2*sizeof(int)];

printf(" Text? "); fgets(buffer,BUFFER_LEN-2*sizeof(int),stdin);

// III. Finished: return(buffer); }

// PURPOSE: To do the work of the application. Gets letter from user, sends // it to server over file-descriptor 'socketFd', and prints returned text. // No return value. void communicateWithServer (int socketFd ) { // I. Application validity check:

// II. Do work of application: // II.A. Get letter from user: char buffer[BUFFER_LEN+1]; int shouldContinue = 1;

while (shouldContinue) { int choice; int fileNum; int numBytes;

do { printf ("What would you like to do: " "(1) List files " "(2) Write file " "(3) Spell check a file " "(4) Delete a file " "(0) Quit " "Your choice? " ); fgets(buffer,BUFFER_LEN,stdin); choice = strtol(buffer,NULL,10); } while ( (choice < 0) || (choice > 5) );

switch (choice) { case 0 : shouldContinue = 0; snprintf(buffer,BUFFER_LEN,"%c",QUIT_CMD_CHAR); break;

case 1 : snprintf(buffer,BUFFER_LEN,"%c",DIR_CMD_CHAR); break;

case 2 : snprintf(buffer,BUFFER_LEN,"%c %d \"%s\"", WRITE_CMD_CHAR,getFileNumber(),getText() ); break;

case 3 : snprintf(buffer,BUFFER_LEN,"%c %d",SPELL_CMD_CHAR,getFileNumber()); break;

case 4 : snprintf(buffer,BUFFER_LEN,"%c %d",DELETE_CMD_CHAR,getFileNumber()); break;

}

printf("Sending \"%s\" ",buffer); write(socketFd,buffer,strlen(buffer)+1); numBytes = read (socketFd,buffer,BUFFER_LEN);

if (numBytes > 0) buffer[numBytes] = '\0';

printf("%s ",buffer); }

// III. Finished: }

// PURPOSE: To do the work of the client. Ignores command line parameters. // Returns 'EXIT_SUCCESS' to OS on success or 'EXIT_FAILURE' otherwise. int main () { char url[BUFFER_LEN]; int port; int socketFd;

obtainUrlAndPort(BUFFER_LEN,url,&port); socketFd = attemptToConnectToServer(url,port);

if (socketFd < 0) exit(EXIT_FAILURE);

communicateWithServer(socketFd); close(socketFd); return(EXIT_SUCCESS); } /*-------------------------------------------------------------------------* *--- ---* *--- wordServer.c ---* *--- ---* *--- This file defines a C program that gets file-sys commands ---* *--- from client via a socket, executes those commands in their own ---* *--- threads, and returns the corresponding output back to the ---* *--- client. ---* *--- ---* *--- ---- ---- ---- ---- ---- ---- ---- ---- ---* *--- ---* *--- Version 1a Joseph Phillips ---* *--- ---* *-------------------------------------------------------------------------*/

// Compile with: // $ gcc wordServer.c -o wordServer -lpthread

//--- Header file inclusion ---//

#include "wordClientServer.h" #include // For pthread_create()

//--- Definition of constants: ---//

#define STD_OKAY_MSG "Okay"

#define STD_ERROR_MSG "Error doing operation"

#define STD_BYE_MSG "Good bye!"

#define THIS_PROGRAM_NAME "wordServer"

#define OUTPUT_FILENAME "out.txt"

#define ERROR_FILENAME "err.txt"

const int ERROR_FD = -1;

//--- Definition of functions: ---//

// PURPOSE: To run the server by 'accept()'-ing client requests from // 'listenFd' and doing them. void doServer (int listenFd ) { // I. Application validity check:

// II. Server clients: pthread_t threadId; pthread_attr_t threadAttr; int threadCount = 0;

// YOUR CODE HERE

// III. Finished: }

// PURPOSE: To decide a port number, either from the command line arguments // 'argc' and 'argv[]', or by asking the user. Returns port number. int getPortNum (int argc, char* argv[] ) { // I. Application validity check:

// II. Get listening socket: int portNum;

if (argc >= 2) portNum = strtol(argv[1],NULL,0); else { char buffer[BUFFER_LEN];

printf("Port number to monopolize? "); fgets(buffer,BUFFER_LEN,stdin); portNum = strtol(buffer,NULL,0); }

// III. Finished: return(portNum); }

// PURPOSE: To attempt to create nd return a file-descriptor for listening // to the OS telling this server when a client process has connect()-ed // to 'port'. Returns that file-descriptor, or 'ERROR_FD' on failure. int getServerFileDescriptor (int port ) { // I. Application validity check:

// II. Attempt to get socket file descriptor and bind it to 'port': // II.A. Create socket int socketDescriptor = socket(AF_INET, // AF_INET domain SOCK_STREAM, // Reliable TCP 0);

if (socketDescriptor < 0) { perror(THIS_PROGRAM_NAME); return(ERROR_FD); }

// II.B. Attempt to bind 'socketDescriptor' to 'port': // II.B.1. We'll fill in this datastruct struct sockaddr_in socketInfo;

// II.B.2. Fill socketInfo with 0's memset(&socketInfo,'\0',sizeof(socketInfo));

// II.B.3. Use TCP/IP: socketInfo.sin_family = AF_INET;

// II.B.4. Tell port in network endian with htons() socketInfo.sin_port = htons(port);

// II.B.5. Allow machine to connect to this service socketInfo.sin_addr.s_addr = INADDR_ANY;

// II.B.6. Try to bind socket with port and other specifications int status = bind(socketDescriptor, // from socket() (struct sockaddr*)&socketInfo, sizeof(socketInfo) );

if (status < 0) { perror(THIS_PROGRAM_NAME); return(ERROR_FD); }

// II.B.6. Set OS queue length: listen(socketDescriptor,5);

// III. Finished: return(socketDescriptor); }

int main (int argc, char* argv[] ) { // I. Application validity check:

// II. Do server: int port = getPortNum(argc,argv); int listenFd = getServerFileDescriptor(port); int status = EXIT_FAILURE;

if (listenFd >= 0) { doServer(listenFd); close(listenFd); status = EXIT_SUCCESS; }

// III. Finished: return(status); } Implementing doServer(int listenFd) (10 Points): doServer() should have a loop in which it waits for a client to connect to listenFd. When a client does, it should:

malloc() enough memory for 2 integers put the file descriptor from accept() in one of those spaces put the value of threadCount in the other space, and increment threadCount Make a detached thread to handle this new client. I called my function handleClient(), but you may call yours whatever. Pass the address of your malloc()-ed array. The loop should then go back for another accept(). void* handleClient(void* vPtr) (10 Points): (Or whatever you call your function that runs a thread for the client.) The thread id and the file descriptor are passed, but they come in as a void* pointer. Use another pointer to cast back to int* Save the file descriptor and thread number in local vars free() the memory Print the thread number and do loop like this: // II.B. Read command: char buffer[BUFFER_LEN]; char command; int fileNum; char text[BUFFER_LEN]; int shouldContinue = 1;

while (shouldContinue) { text[0] = '\0';

read(fd,buffer,BUFFER_LEN); printf("Thread %d received: %s ",threadNum,buffer); sscanf(buffer,"%c %d \"%[^\"]\"",&command,&fileNum,text);

// YOUR CODE HERE } It read()s a line of text from the client into buffer[], and parses the line into a command character, fileNum integer, and quote-delineated text[] string. (The fileNum and text[] may or may not be given, depending upon the value of command.)

Then do the following operations based upon the value of command. Except for QUIT_CMD_CHAR I strongly recommend using a different function for each!

When the function ends just have it do:

printf("Thread %d quitting. ",threadNum); return(NULL); command == DIR_CMD_CHAR (15 Points): Open the current directory (named "."). If an error occurs then just send STD_ERROR_MSG back to the client. Copy as many entries that will fit into a buffer of length BUFFER_LEN. Be sure to put a separating ' ' after each entry. Close the directory. command == WRITE_CMD_CHAR (15 Points): This one should open the file numbered fileNum for output. Then it should write text from the client to that file. If there is an error send then send STD_ERROR_MSG back to the client. If you succeeded then send STD_OKAY_MSG back to the client.

command == SPELL_CMD_CHAR (30 Points): This one spell checks a file numbered fileNum by:

Opening it in read-write mode. If opening the file fails then it sends STD_ERROR_MSG back to the client. Putting ENDING_TEXT (a purposeful misspelling) at the end of the file. We so we can look for it in the output of the spell-checker: when we see it we know we have seen all the output. If fileFd is the file-descriptor of your input-output file you can do with: long length = lseek(fileFd,0,SEEK_END); int status = write(fileFd,ENDING_TEXT,sizeof(ENDING_TEXT)-1); Opens a pipe for the spell-checking child process to communicate back to the parent. If opening the pipe fails then it sends STD_ERROR_MSG back to the client. fork()s a child process. The child process resets its position in the input-output file back to the beginning of the file. It then has its input re-directed from the file descriptor of the file, and its output re-directed to the output side of the pipe. If fileFd is the file-descriptor of your input-output file, and fromSpeller[] is your pipe, you mayo this with: lseek(inFileFd,0,SEEK_SET); dup2(inFileFd,STDIN_FILENO); dup2(fromSpeller[1],STDOUT_FILENO); Then, the child process executes program SPELLER_PROGNAME with command line argument SPELLER_PROG_OPTION. If the child process cannot execute the program, then it sends STD_ERROR_MSG and ENDING_TEXT back to the parent process using the pipe and does exit(EXIT_FAILURE). Meanwhile, in a loop the parent process continually read()s from the input end of the pipe. Whatever it read()s it should put into a buffer which it will send back to the client. When it finds ENDING_TEXT it knows the input has ended, and it can quit the loop. Look for one string inside of another with strstr(). After the read()ing loop the parent process should: wait() for the child process to end remove ENDING_TEXT from the input-output file ftruncate(fileFd,length); close() that file and the pipe command == DELETE_CMD_CHAR (10 Points): fileNum tells the file number of the file to delete. Using the unlink() command. If there is an error send then send STD_ERROR_MSG back to the client. If you succeeded then send STD_OKAY_MSG back to the client.

command == QUIT_CMD_CHAR (10 Points): Just send STD_BYE_MSG back to the client and set shouldContinue to 0 to quit the loop.

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

Step: 3

blur-text-image

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

Financial management theory and practice

Authors: Eugene F. Brigham and Michael C. Ehrhardt

12th Edition

978-0030243998, 30243998, 324422695, 978-0324422696

Students also viewed these Programming questions