Question: 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 malloc()s memory to store both the loop variable i and the file descriptor from accept() for talking to the client. It then pthread_create()s a child to handle the client and gives it the malloc()ed memory. All of the threads except the last (i == (NUM_CLIENTS_TO_SERVE-1)) should be detached threads. The last thread should be an ordinary, joinable thread, which the parent thread should join with outside the loop.
The child thread should:
Get the thread id (coming in as the loop variable) and file descriptor. It then free()s that malloc()ed memory.
Gets the letter from the client
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 its id and "id num: Cannot read directory ",
returns NULL.
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.
If the server finds no matching file then it
sends NO_MATCH_CODE back to the client (in network endian),
prints its id and "id num: No matching file ",
returns NULL.
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 its id and "id num: Cannot read file
returns NULL.
Prints its id and "id num: Sending
Sends the size of the file as a uint32_t integer to the client (in network endian)
Sends the bytes of the file to the client. It should send the file in buffers of bytes of size BUFFER_LEN.
close()s what it should close.
returns NULL.
/*-------------------------------------------------------------------------* *--- ---* *--- 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. *--- ---* *--- ---- ---- ---- ---- ---- ---- ---- ---- ---* *--- ---* *--- ---* *-------------------------------------------------------------------------*/ // // Compile with: // $ gcc server_getFileByFirstLetter.c -o server -lpthread // /*--- Header file inclusion ---*/ #include "getFileByFirstLetter.h" #include// For opendir(), readdir(), closedir() #include // For pthread_create(), etc. 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 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.A. Create a socket int socketDescriptor = socket(AF_INET, // AF_INET domain SOCK_STREAM, // Reliable TCP 0); if (socketDescriptor < 0) { perror(progName); 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(progName); return(ERROR_FD); } // II.B.6. Set OS queue length: listen(socketDescriptor,5); // III. Finished: return(socketDescriptor); } // 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 pointed to by '*vPtr'. Returns // 'NULL'. void* handleClient (void* vPtr ) { // I. Application validity check: // II. Handle the client: // YOUR CODE HERE // III. Finished: return(NULL); } // 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; pthread_t tId; pthread_attr_t tAttr; pthread_attr_init(&tAttr); pthread_attr_setdetachstate(&tAttr,PTHREAD_CREATE_DETACHED); for (i = 0; i < NUM_CLIENTS_TO_SERVE; i++) { // YOUR CODE HERE } pthread_join(tId,NULL); pthread_attr_destroy(&tAttr); // 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]); doServer(socketFd); // III. Finished: return(EXIT_SUCCESS); }
Step by Step Solution
There are 3 Steps involved in it
Get step-by-step solutions from verified subject matter experts
