Exercise: You will use the TCP echo client and server code (for IPv4 version) from Donahoo. You will modify the code to do the following. Instead of transmitting a string (passed from the command line) from client to server, you will pass a text file as a command line argument, and transmit the contents of that file to the sender line by line, including line numbers. (Sample file is attached to Canvas). The rest of the arguments will remain the same. While sending data, client will echo it line by line to the screen, along with line numbers. Please keep in mind that your program should work with any file, not just the one that was provided, so hard-coding will not be a good idea. The server will receive the entire file, buffer it until it has the entire contents, and then reverse it and echo (print) it to the standard output (screen). Each revesed line of text will have the correct line number. The last character of the original file will be the first one in the reversed version except line numbes. After that you will print a goodbye message from both the client and the server and close the connection. It is up to you to figure out the details. There are several different solutions to this problem, and everyone's solution may be different. I do recommend that you review how to read from files in C and go over the code line by line following the Chapter 2 in Donahoo. Starter Code: TCPEchoServer4.c: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include "Practical.h" #include <unistd.h> static const int MAXPENDING = 5; // Maximum outstanding connection requests int main(int argc, char *argv[]) { if (argc != 2) // Test for correct number of arguments DieWithUserMessage("Parameter(s)", "<Server Port>"); in_port_t servPort = atoi(argv[1]); // First arg: local port // Create socket for incoming connections int servSock; // Socket descriptor for server if ((servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithSystemMessage("socket() failed"); // Construct local address structure struct sockaddr_in servAddr; // Local address memset(&servAddr, 0, sizeof(servAddr)); // Zero out structure servAddr.sin_family = AF_INET; // IPv4 address family servAddr.sin_addr.s_addr = htonl(INADDR_ANY); // Any incoming interface servAddr.sin_port = htons(servPort); // Local port // Bind to the local address if (bind(servSock, (struct sockaddr*) &servAddr, sizeof(servAddr)) < 0) DieWithSystemMessage("bind() failed"); // Mark the socket so it will listen for incoming connections if (listen(servSock, MAXPENDING) < 0) DieWithSystemMessage("listen() failed"); for (;;) { // Run forever struct sockaddr_in clntAddr; // Client address // Set length of client address structure (in-out parameter) socklen_t clntAddrLen = sizeof(clntAddr); // Wait for a client to connect int clntSock = accept(servSock, (struct sockaddr *) &clntAddr, &clntAddrLen); if (clntSock < 0).