Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

Please finish the server of a client-server application. The client asks the user for a letter (a character in {A-Z,a-z}), and then sends that letter

Please finish the server of a client-server application. The client asks the user for a letter (a character in {A-Z,a-z}), and then sends that letter to the server. The server fork()s a child to handle the client, and that child process:

1. Gets the letter from the client

2. Attempts to open the current directory ("."). If it cannot open that directory then it:

-sends CANT_READ_DIR_CODE back to the client (in network endian),

-prints "Cannot read directory ",

-returns.

3. Iterates thru the directory to looking for a file (not a directory or anything else) whose name starts with the letter obtained from the client.

4. If the server finds no matching file then it

-sends NO_MATCH_CODE back to the client (in network endian),

-prints "No matching file ",

-returns.

5. Attempts to open the file for reading. If it cannot open the file then it:

-sends CANT_READ_FILE_CODE back to the client (in network endian),

-prints "Cannot read file ",

-returns.

6. Prints "Sending , bytes "

7. Sends the size of the file as a uint32_t integer to the client (in network endian)

8. Sends the bytes of the file to the client. It should send the file in buffers of bytes of size BUFFER_LEN.

9. close()s what it should close.

Code:

/*-------------------------------------------------------------------------* *--- ---* *--- getFileByFirstLetter.h ---* *--- ---* *--- This file declares constants common to both the client and *--- server of an application where the client asks the user for a ---* *--- letter, and then asks a server for the text of a file that ---* *--- begins with that letter. ---* *--- ---* *--- ---- ---- ---- ---- ---- ---- ---- ---- ---* *--- ---* *--- Version 1.0 2018 March 5 Joseph Phillips ---* *--- ---* *-------------------------------------------------------------------------*/ /*--- Header file inclusion ---*/ #include  #include  #include  #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 256 #define NO_MATCH_CODE ((uint32_t) -1) #define CANT_READ_FILE_CODE ((uint32_t) -2) #define CANT_READ_DIR_CODE ((uint32_t) -3) #define DEFAULT_HOSTNAME "localhost" /*-------------------------------------------------------------------------* *--- ---* *--- client_getFileByFirstLetter.c ---* *--- ---* *--- This file defines a C program that asks the user for a ---* *--- letter, and then asks a server for the text of a file that ---* *--- begins with that letter. ---* *--- ---* *--- ---- ---- ---- ---- ---- ---- ---- ---- ---* *--- ---* *--- Version 1.0 2018 March 5 Joseph Phillips ---* *--- ---* *-------------------------------------------------------------------------*/ /*--- Header file inclusion ---*/ #include "getFileByFirstLetter.h" #include  // isalpha() // 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 a 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 do the work of the application. Gets letter from user, sends // it to server over file-descriptor 'fd', and either prints text of // returned error code, or prints returned file. No return value. void communicateWithServer (int fd ) { // I. Application validity check: // II. Do work of application: // II.A. Get letter from user: char buffer[BUFFER_LEN+1]; do { printf("Please enter a letter to look for: "); fgets(buffer,BUFFER_LEN,stdin); } while ( !isalpha(buffer[0]) ); // II.B. Send letter to server: write(fd,buffer,1); // II.C. Get response from server: uint32_t fileSize; read(fd,&fileSize,sizeof(fileSize)); fileSize = ntohl(fileSize); // II.D. Interpret server response: switch (fileSize) { case NO_MATCH_CODE : printf("No matching file found for %c ",buffer[0]); break; case CANT_READ_FILE_CODE : printf("Matching file found for %c, but could not open ",buffer[0]); break; case CANT_READ_DIR_CODE : printf("Server could not open . ",buffer[0]); break; default : { unsigned int totalNumBytesRead = 0; int numBytesRead; printf("The file that matches %c has size %u ",buffer[0],fileSize); while ( (totalNumBytesRead < fileSize) && ( (numBytesRead = read(fd,buffer,BUFFER_LEN)) > 0) ) { buffer[numBytesRead] = '\0'; printf("%s",buffer); totalNumBytesRead += (unsigned int)numBytesRead; } } } // 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 fd; obtainUrlAndPort(BUFFER_LEN,url,&port); fd = attemptToConnectToServer(url,port); if (fd < 0) exit(EXIT_FAILURE); communicateWithServer(fd); close(fd); return(EXIT_SUCCESS); } /*-------------------------------------------------------------------------* *--- ---* *--- server_getFileByFirstLetter.c ---* *--- ---* *--- This file defines a C program that waits for a client to ---* *--- connect, gets a letter from the client, and looks for a file in ---* *--- the current directory that begins with that letter. If it ---* *--- finds such a file then it sends the length of the file back as ---* *--- a network-endian 32-bit unsigned integer, followed by the text ---* *--- of the file. Sends back the appropriate error integer code ---* *--- otherwise. *--- ---* *--- ---- ---- ---- ---- ---- ---- ---- ---- ---* *--- ---* *--- Version 1.0 2018 March 5 Joseph Phillips ---* *--- ---* *-------------------------------------------------------------------------*/ /*--- Header file inclusion ---*/ #include "getFileByFirstLetter.h" #include  // For sigaction() #include  // For waitpid() #include  // For opendir(), readdir(), closedir() const int LO_LEGAL_PORT = 1025; const int HI_LEGAL_PORT = 65535; const int ERROR_FD = -1; const int NUM_CLIENTS_TO_SERVE = 4; // PURPOSE: To get zombie children. Ignores 'sig' (which will be 'SIGCHLD'). // No return value. void sigChildHandler (int sig ) { // I. Application validity check: // II. Get all zombie children: // YOUR CODE HERE // III. Finished: } // PURPOSE: To attempt to create and 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, const char* progName ) { // I. Application validity check: if (progName == NULL) { fprintf(stderr,"BUG: NULL ptr to getServerFileDescriptor(). "); exit(EXIT_FAILURE); } // II. Attempt to get socket file descriptor and bind it 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(progName); return(ERROR_FD); } // II.B.6. Set OS queue length: listen(socketDescriptor,5); // III. Finished: return(socketDescriptor); } // PURPOSE: To install 'sigChildHandler()' as the signal simple handler for // the 'SIGCHLD' signal. Tells OS to restarts system calls if receives // 'SIGCHLD'. void installSigChildHandler () { // I. Application validity check: // II. Install 'sigChildHandler()' as the 'SIGCHLD' handler: // YOUR CODE HERE // III. Finished: } // PURPOSE: To ask the user which port to attempt to monopolize, and to return // entered port number. int getPort () { // I. Application validity check: // II. Get port number int port; do { char buffer[BUFFER_LEN]; printf("Please enter port number to monopolize [%d-%d]: ", LO_LEGAL_PORT,HI_LEGAL_PORT ); fgets(buffer,BUFFER_LEN,stdin); port = strtol(buffer,NULL,10); } while ( (port < LO_LEGAL_PORT) || (port > HI_LEGAL_PORT) ); // III. Finished: return(port); } // PURPOSE: To do the work of handling the client. Communication with the // client take place using file-descriptor 'fd'. No return value. void handleClient (int fd ) { // I. Application validity check: if (fd < 0) { fprintf(stderr,"BUG: Illegal file descriptor to handleClient() "); exit(EXIT_FAILURE); } // II. Handle the client: // YOUR CODE HERE // III. Finished: } // PURPOSE: To serve the clients using file-descriptor 'listenFd' to tell // when a client has connected. Each client is handled by its own child // process. Both the parent and the child processes close unnecesary // file-descriptorors. Serves 'NUM_CLIENTS_TO_SERVE' clients, then quits. // No return value. void doServer (int listenFd ) { // I. Application validity check: if (listenFd < 0) { fprintf(stderr,"Illegal file-descriptor to doServer() "); exit(EXIT_FAILURE); } // II. Do the work of the server: int i; for (i = 0; i < NUM_CLIENTS_TO_SERVE; i++) { // YOUR CODE HERE } // III. Finished: } // PURPOSE: To oversee the main work of the server. Ignores 'argc' but // uses 'argv[0]' as the name of the program. Returns 'EXIT_SUCCESS' to // OS on success or 'EXIT_FAILURE' otherwise. int main (int argc, char* argv[] ) { // I. Application validity check: // II. Do server: int port = getPort(); int socketFd = getServerFileDescriptor(port,argv[0]); installSigChildHandler(); doServer(socketFd); // III. Finished: return(EXIT_SUCCESS); } 

Sample output:

To properly test this program I made a directory called Dir:

$ mkdir Dir 

I also made a file that I did have permission to read called holdYourHeadUp.txt, and one that I did not called youCantOpenMe.txt. The contents of the second file can be whatever you want, but to make it so you cannot open it say:

$ chmod a-rwx youCantOpenMe.txt  

My directory now has:

$ ls 20156-3Spr_CSC407-Assign4.html holdYourHeadUp.txt client server client_getFileByFirstLetter.c server_getFileByFirstLetter.c Dir youCantOpenMe.txt getFileByFirstLetter.h 

Client output: Server output:
 
$ ./server  Please enter port number to monopolize [1025-65535]: 1025 
$ ./client  Machine name [localhost]? (I just pressed enter)  Port number? 1025 Please enter a letter to look for: X No matching file found for X 
No file begins with X:
No matching file Child 5490 finished. 
$ ./client  Machine name [localhost]? (I just pressed enter)  Port number? 1025 Please enter a letter to look for: D No matching file found for D 
Dir begins with D, but it is not a file.
No matching file Child 5497 finished. 
$ ./client  Machine name [localhost]? (I just pressed enter)  Port number? 1025 Please enter a letter to look for: y Matching file found for y, but could not open 
The server cannot open youCantOpenMe.txt.
Cannot read file youCantOpenMe.txt Child 5503 finished. 
$ ./client  Machine name [localhost]? (I just pressed enter)  Port number? 1025 Please enter a letter to look for: h The file that matches h has size 437 And if it's bad Don't let it get you down, you can take it And if it hurts Don't let them see you cry, you can make it Hold your head up, woman Hold your head up, woman Hold your head up, woman Hold your head high Hold your head up, woman Hold your head up, woman Hold your head up, woman Hold your head high And if they stare Just let them burn their eyes on you moving And if they shout Don't let it change a thing that you're doing 
The server can open holdYourHeadUp.txt, so it sends it to the client.
Sending holdYourHeadUp.txt, 437 bytes And if it's bad Don't let it get you down, you can take it And if it hurts Don't let them see you cry, you can make it Hold your head up, woman Hold your head up, woman Hold your head up, woman Hold your head high Hold your head up, woman Hold your head up, woman Hold your head up, woman Hold your head high And if they stare Just let them burn their eyes on you moving And if they shout Don't let it change a thing that you're doing 

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

Professional Microsoft SQL Server 2014 Administration

Authors: Adam Jorgensen, Bradley Ball

1st Edition

111885926X, 9781118859261

More Books

Students also viewed these Databases questions