Question
Program 2 Specifications ***Please Read the following Requirement, need to create WSEchoServer6.c and ProcessClient.c file, not WSClientServerv6.c!!!*** Name your source code files WSEchoServerv6.c and ProcessClient.c
Program 2 Specifications
***Please Read the following Requirement, need to create WSEchoServer6.c and ProcessClient.c file, not WSClientServerv6.c!!!***
Name your source code files WSEchoServerv6.c and ProcessClient.c. Use the DisplayFatalErr.c module from Program 1 to handle errors. Use your own WSEchoClientv6.exe(Program 1) to test your server. This program will be implemented as a command line program in C. It will obtain its input data from one command line argument, as follows:
WSEchoServerv6
For example: WSEchoServerv6 5000
You may design your server to use a default port number if none is provided as a command line argument. When starting your server, use a port number above the range of well-known port numbers (1 1024).
All network communication will be achieved using the Windows Sockets API. Do not use C++ socket classes.
Include the program number, and your name, section, date, Windows version and Visual Studio version in the program header comments.
Include the header(.h) files required to support Windows Sockets.
Use C or C++ style comments to document each call to the WinSock API. Refer toProgramming Assignments/Program 1/style.pdfin Canvas for style guidelines.
Feel free to insert additional printf() and getchar()statements into your server code for debugging purposes, but you must remove them and recompile before submitting your program to Canvas, so that the grader doesnt have to press ENTER repeatedly to get your server to accept a client connection and echo the message. Failing to do this may lower your score.
Code the following required procedural activities in the order listed.
1.The primary source code file will be named WSEchoServerv6.c. This will contain your main()function. As with your client, verify the correct number of command line arguments have been provided by the user. You dont need to validate the content of those arguments.If no port number is included on the command line, you may use a default port of your own choosing.
2. Initialize the WinSock DLL.After a successful call to WSAStartup(), handle any errors by callingDisplayFatalErr().
3.Create the server socket.
4.Load the server information into the servers sockaddr_in6structure (see Lecture 12 slide titled Server Socket Initialization). Use in6addr_anyas the servers IP address.
5.bind()the server socket tothissockaddr_in6structure.
6.Call listen() to tell the server the maximum simultaneous client connection requests to allow.
7.Display a message on the server console that includes your initials, similar to this:JD's IPv6 echo server is ready for client connection...
8.Enter a forever loop like this:for (;;){...}From within this loop, call accept()and wait for a client connection. Calling accept() from within this for loop will allow the server to accept connection requests from one or more clients, but only one at a time. Echo back one complete client message per connection request. (This non-threaded program will not support multiple simultaneous client connections.)
9.Each time a client connects to the server in this loop, display the IP address and port number of the client, and the servers own port number (from the servers sockaddr_in6) on the servers console, as shown below:
Processing the client at
For example: Processing the client at ::1, client port 54321, server port 5000
Use inet_ntop()to convert an IP address from network format into a text string suitable for display(as shown above). Use ntohs()to convert a 16-bit port number from network format back into a 16-bit Windows integer.Verify that both port numbers are displayed as numerically correct values (not reversed).
10. From within the foreverloop, call a function named ProcesClient()to receive the message from your client. Implement ProcesClient() in a separate source code file named ProcessClient.c. Declare ProcessClient() in WSEchoServerv6.c, outside of main(), the same way that DisplayFatalError()is declared. Check for errors in theSockets receive process, as indicated by a negative return value from recv().
11.Echo the message back to the client from within ProcessClient(). Be sure that all of the clients message has been received and echoed by the server.You cant count bytes as you did with the client, because the server doesnt know in advance how many bytes to expect from the client, and whether all of those bytes will be received in the initial call to recv(). So call recv() repeatedly until recv()returns message length 0, indicating that the client has closed the connection. (See the Lecture 11 slide titled recv( ) for details.)
12.While still inProcessClient(), close the client socket, return to the forever loop in WSEchoServerv6.c, then call accept()and wait for another client connection.
13.While waiting in the forever loop for client communication, the server can be terminated with CTRL+C. No special programming is required to enable this. Note that CTRL+C works when running the server from the command line, but not if you are running it in the Visual Studio debugger.Because we are using this crude termination mechanism for the server, no call to closesocket() will be needed to close the server socket and no call toWSACleanup()will be needed to release the WinSock DLL resources. Those functions will be handled by the operating system. (In a real sockets program, omitting closesocket() and WSACleanup() would be considered poor design.)
Testing Your Echo Server
Design and code your echo server, build the solution and debug any compiler errors. After your program compiles successfully, test it with your client in loopback mode, running both programs from the command line. Start the server first, like this: WSEchoServerv6
WSEchoClientv6::1
Verify that your server echoes the message back to your client, and that the client can reconnect and echo another message while the server continues running.If not, debug the server.
Source code for WSEchoClientv6.c:
// Minimum required header files for C Winsock program #include
// #define ALL required constants HERE, not inline // #define is a macro, don't terminate with ';' For example... #define RCVBUFSIZ 50
// declare any functions located in other .c files here void DisplayFatalErr(char* errMsg); // writes error message before abnormal termination
void main(int argc, char* argv[]) { // Declare ALL variables and structures for main() HERE, NOT INLINE (including the following...) WSADATA wsaData; // contains details about WinSock DLL implementation struct sockaddr_in6 serverInfo; // standard IPv6 structure that holds server socket info
// Verify correct number of command line arguments if (argc != 4) { fprintf(stderr, "Invalid number of arguments! "); exit(1); // ...and terminate with abnormal termination code (1) }
// Retrieve the command line arguments. (Sanity checks not required, but port and IP addr will need // to be converted from char to int. See slides 11-15 & 12-3 for details.) int port = 0; int ip = 0; __try { ip = atoi(argv[1]); port = atoi(argv[2]); } __except (printf("bad IP or Port")) { exit(1); }
// Initialize Winsock 2.0 DLL. Returns 0 if ok. If this fails, fprint error message to stderr as above & exit(1). WSAStartup(MAKEWORD(2, 0), &wsaData); // Create an IPv6 TCP stream socket. int sock; __try { sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); } //Now that Winsock DLL is loaded, we can signal any errors as shown on next line : __except (INVALID_SOCKET) { DisplayFatalErr("socket() function failed."); } // Display helpful confirmation messages after key socket calls like this: printf("Socket created successfully. "); int perrno = -1; int v6Only = 0; // If doing extra credit IPv4 address handling option, add the setsockopt() call as follows... if (perrno = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6Only, sizeof(v6Only)) != 0) DisplayFatalErr("setsockopt() function failed.");
// Zero out the sockaddr_in6 structure and load server info into it. See slide 11-15. // Don't forget any necessary format conversions. struct sockaddr_in6 serverinfo;
// Server IP address and port number come from the client command line char* serverIPaddr = argv[1];//argv[1] is 1 in our test case looping back locally for ipv6. unsigned short serverPort = atoi(argv[2]); memset(&serverInfo, 0, sizeof(serverInfo));
// Load server info into sockaddr_in6 serverInfo.sin6_family = AF_INET6; serverInfo.sin6_port = htons(serverPort); // Convert cmd line server addr from char to ntwk form, load into sockaddr_in6 inet_pton(AF_INET6, serverIPaddr, &serverInfo.sin6_addr); int msgLen = strlen(argv[3]); // Attempt connection to the server. If it fails, call DisplayFatalErr() with appropriate message, // otherwise printf() confirmation message if (connect(sock, (struct sockaddr*) & serverInfo, sizeof(serverInfo)) < 0) { DisplayFatalErr("connect() function failed."); } else { printf("Connection succcessful "); }
// Send message to server (without '\0' null terminator). Check for null msg (length=0) & verify all bytes were sent... int sent = send(sock, argv[3], msgLen, 0); if (sent != msgLen) { DisplayFatalErr("send failed."); } else { printf("trying to receive from server "); int bytesRead = 0; int buffLength = (int)strlen(argv[3]); char rcvBuffer[RCVBUFSIZ]; int byteTracker = 1; memset(rcvBuffer, 0, strlen(rcvBuffer)); printf("reading back message: "); // Retrieve the message returned by server. Be sure you've read the whole thing (could be multiple segments). // Manage receive buffer to prevent overflow with a big message.
// Display ALL of the received message, in printable C string format. while (bytesRead != msgLen) { // if recv fails, DisplayFatalErr() with appropriate message as before byteTracker = recv(sock, rcvBuffer, RCVBUFSIZ - 1, 0); // Call DisplayFatalErr() if this fails. (Lots can go wrong here, see slides.) if (byteTracker < 0) { DisplayFatalErr("Receive failed."); } bytesRead += byteTracker; //routine 1: get entire string in 1 try: if (byteTracker == msgLen) { rcvBuffer[strlen(rcvBuffer)] = 0; printf(rcvBuffer); } //routine 2: get less than entire string in 1 try: else if (bytesRead <= msgLen) { rcvBuffer[strlen(rcvBuffer)] = 0; printf(rcvBuffer); } memset(rcvBuffer, 0, strlen(rcvBuffer)); } printf(" Bytes read: %d ", bytesRead); } // Close the TCP connection (send a FIN) & print appropriate message. closesocket(sock);
// Release the Winsock DLL
WSACleanup(); exit(0); }
DisplayFatalErr.c
// Minimum required header files for C Winsock program
#include
#include
#include
void DisplayFatalErr(char *errMsg) {
fprintf(stderr, "%s: %d ", errMsg, WSAGetLastError()); // Returns error code from current task or thread
WSACleanup();
exit(1);
}
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started