1 / 37

Computer Networks

Computer Networks. Project 1 Prof. Jerry Breecher. What You Will Do In This Project. The purpose of this project is to build a simple Web Server. This project is similar to the Project 1 as defined by Kurose and Ross. You’ll be developing your code in C or C++ rather than in Java, however.

Télécharger la présentation

Computer Networks

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Computer Networks Project 1 Prof. Jerry Breecher Networks - Project 1

  2. What You Will Do In This Project. The purpose of this project is to build a simple Web Server. This project is similar to the Project 1 as defined by Kurose and Ross. You’ll be developing your code in C or C++ rather than in Java, however. You have two tasks before you: • Develop a portion of your web server – just enough to display what a browser typically sends at a server. • Develop a web server that can respond to the browser and return the requested information. Networks - Project 1

  3. Where To Get Help In the writeups for Projects 0 and 1, there is information on where to find help. You may or may not have needed the help then, but remember it’s there. Learning C: Learning GDB – how to debug: Learning UNIX: All of these skills can be acquired (I hope) from the documentation available on my webpage – see the bottom of the page at babbage.clarku.edu/~jbreecher If you don’t like these documents, there are plenty of other ones out on the web. Go wild! Networks - Project 1

  4. Where To NOT Get Help It is NOT acceptable for you to get code from your classmates. You can talk about general concepts with your colleagues, but I expect that you have written your own code. You will be handing in your code, and I will be reading it. One of the things I will be looking for (sigh) is signs of copying other people’s work. Networks - Project 1

  5. Building a Multi-Threaded Web Server In this lab we will develop a Web server in two steps. In the end, you will have built a multi-threaded Web server that is capable of processing multiple simultaneous service requests in parallel. You should be able to demonstrate that your Web server is capable of delivering your home page as well as other web pages to a Web browser. On the Kurose and Ross web page, you can find the original text for this document. I have modified it in order to make it easy for you to do the coding in C or C++. We are going to implement version 1.0 of HTTP, as defined in RFC 1945, where separate HTTP requests are sent for each component of the Web page. The server will be able to handle multiple simultaneous service requests in parallel. This means that the Web server is multi-threaded. In the main thread, the server listens to a fixed port. When it receives a TCP connection request, it sets up a TCP connection through another port and services the request in a separate thread. Networks - Project 1

  6. Building a Multi-Threaded Web Server To simplify this programming task, we will develop the code in two stages. In the first stage, you will write a multi-threaded server that simply displays the contents of the HTTP request message that it receives. After this program is running properly, you will add the code required to generate an appropriate response. As you are developing the code, you can test your server from a Web browser. But remember that you are not serving through the standard port 80, so you need to specify the port number within the URL that you give to your browser. For example, if your machine's name is iverson.clarku.edu, and if your server is listening to port 6789, and if you want to retrieve the file index.html, then you would specify the following URL within the browser: http://iverson.clarku.edu:6789/index.html If you omit ":6789", the browser will assume port 80 which will either not have a server listening on it or will have apache listening. When the server encounters an error, it sends a response message with the appropriate HTML source so that the error information is displayed in the browser window. Networks - Project 1

  7. Web Server in C: Part A In the following steps, we will go through the code for the first implementation of our Web Server. Wherever you see "?", you will need to supply a missing detail. Our first implementation of the Web server will be multi-threaded, where the processing of each incoming request will take place inside a separate thread of execution. This allows the server to service multiple clients in parallel, or to perform multiple file transfers to a single client in parallel. When we create a new thread of execution, we need to pass to the Thread, information about the socket that’s just been accepted from the remote browser. See the diagram on the next page to better understand this. Networks - Project 1

  8. Overview Of Operation Web Browser Your Web Server Connect Send Receive Accept( new_socket ) Create_thread New Thread Receive Send Networks - Project 1

  9. For your amusement and edification, the code for a working multithreaded program is given in Appendix A. You would be wise to run that program just to see how it works. The skeleton of your Web server is contained in that multithreaded example from that Appendix: Web Server in C: Part A #include <stdio.h> #include <pthread.h> #include <sys/resource.h> #include <asm/errno.h> int WorkThread( void * ); // Prototype unsigned int CreateAThread( void *, int *); // Prototype // /////////////////////////////////////////////////////////////////////// // This is the main() code - it is the original thread // /////////////////////////////////////////////////////////////////////// main() { unsigned int CurrentPriority, MyPid; unsigned int NewThreadID; // Create a new thread that will start executing at location WorkThread NewThreadID = CreateAThread( (void *)(*WorkThread), &data); // Other main code } // End of main // This is the new thread that's created int WorkThread( void *data ) { } // End of WorkThread Networks - Project 1

  10. Web Server in C: Part A Normally, Web servers process service requests that they receive through well-known port number 80. You can use one of the ports assigned to you, but remember to use the same port number when making requests to your Web server from your browser. In our example here, we’ll use port 6789. // This is the main() code - it is the original thread main() { int port = 6789; // Set the port number. Networks - Project 1

  11. Web Server in C: Part A Next, we open a socket and wait for a TCP connection request. Because we will be servicing request messages indefinitely, we place the accept operation inside of an infinite loop. This means we will have to terminate the Web server by pressing ^C on the keyboard. Note that the socket / bind / listen / accept sequence is the same as it was in Project 0. // Establish the socket that will be used for listening fd = socket( ????? ) // Do a bind of that socket bind( fd, ???? ) // Set up to listen listen( fd, ??? ) fdListen = fd; while( TRUE ) { // Do the accept fdconn = accept( fdListen, ???? ) Networks - Project 1

  12. When a connection request is received, we create a thread, passing to that thread a reference to the new Socket, fdconn, that represents our established connection with the client. The thread creation routine wants data of type (void *) so we cast fdconn going into the routine, and then cast it back when we get into WorkThread. Web Server in C: Part A while(TRUE) { // Do the accept fdconn = accept( fdListen, ???? ) out = CreateAThread( (void *)(*WorkThread), &fdConn); } // End of while } // End of main // This is the new thread that's created int WorkThread( void *data ) { int fdConn; fdConn = (int)data; } // End of WorkThread After the new thread has been created, execution in the main thread returns to the top of the while loop. The main thread will then block on accept, waiting for another TCP connection request, while the new thread continues running. When another browser request is received, the main thread goes through the same thread creation regardless of whether the previous thread has finished execution or is still running. Networks - Project 1

  13. Web Server in C: Part A After the new thread has been created and started, execution in the main thread returns to the top of the message processing loop. The main thread will then block, waiting for another TCP connection request, while the new thread continues running. When another TCP connection request is received, the main thread goes through the same process of thread creation regardless of whether the previous thread has finished execution or is still running. This completes the code in main(). For the remainder of the lab, we’ll be talking about what happens in the new thread WorkThread. Networks - Project 1

  14. Web Server in C: Part A So now we start talking about our new thread WorkThread. It’s easiest to think of this simply as a subroutine. It’s as if main is calling this as a routine, except that it’s got this new language that defines it as a thread. And of course, as a new thread, the code for main and WorkThread can both operate independent of each other. The thread creation code requires that the argument passed to the new thread must be of type (void *) – a pointer to a void. So in main, we cast fdConn, the new socket in that form. Then in WorkThread, since we know what’s been passed in is actually a socket (of type int), we cast it back to that form. out = CreateAThread( (void *)(*WorkThread), (void *)fdConn); // This is the new thread that's created int WorkThread( void *InputConnection ) { ----------------------- ----------------------- int fdConn; fdConn = (int)InputConnection; Networks - Project 1

  15. Web Server in C: Part A Now, let's develop the code within WorkThread. We declare an input buffer to hold the data we’re getting from the client. Then we zero out the buffer – who knows what kind of junk is in that data space? #define BUFFERSIZE 1000 int WorkThread( void *InputConnection ) { char ip_input_buffer[BUFFERSIZE]; bzero( ip_input_buffer, sizeof( ip_input_buffer )); Then we get the client’s request message which we do with a recv(). The amount of data taken in will be the lesser of the amount of data in the system ready to be received, OR the size of our buffer. Recv returns the number of bytes it’s received so we keep reading until nothing more is taken in. bzero( ip_input_buffer, sizeof( ip_input_buffer )); while ( recv( ?? ) > 0 ) { printf( “%s\n”, ip_input_buffer ); } Networks - Project 1

  16. Web Server in C: Part A That last code was very interesting. We could take in 1 byte or we could take in up to BUFFERSIZE bytes with each recv – we don’t know so we just keep reading until we don’t get anything more. When we’re done reading and printing data, then simply close the connection as shown. close(???); } // End of WorkThread Networks - Project 1

  17. Web Server in C: Part A That’s all the code we write for Part A. Our web server isn’t “serving” yet – all it’s doing is printing out what the client hands it – but that’s interesting to see. After your program successfully compiles, run it with an available port number, and try contacting it from a browser. To do this, you should enter into the browser's address text box the IP address of your running server. For example, if your machine name is babbage.clarku.edu, and you ran the server with port number 6789, then you would specify the following URL: http:// babbage.clarku.edu:6789/ The server should display the contents of the HTTP request message. Check that it matches the message format shown in the HTTP Request Message diagram in Section 2.2 of the textbook. Networks - Project 1

  18. Web Server in C: Part B • Instead of simply terminating the thread after displaying the browser's HTTP request message, we will analyze the request and send an appropriate response. • Here are the steps we’ll follow: • There will be NO new code in main – everything is in WorkThread. • In WorkThread, change the “while (recv…)” so that it does just one receive. • Check that the client really gave us a “GET” request. • Extract and massage the filename the client wants to see. • If the file does not exist, pass back an error message to the client. • If the file does exist, prepare a header and then pass back the file to the client. Networks - Project 1

  19. Web Server in C: Part B The code we defined in Part A of the WorkThread looked like this: while ( recv( ?? ) > 0 ) { printf( “%s\n”, ip_input_buffer ); } This does nothing but loop as long as data is available to be received. Instead, we want to receive data just once (assume your BUFFERSIZE is BIG so that all the data from the browser will arrive at once) so the code looks like this: if ( recv( ?? ) <= 0 ) printf( "Took an error on recv of data from browser\n" ); else { // This is where we go after a successful receive. } Networks - Project 1

  20. Web Server in C: Part B We are going to ignore the information in the header lines, and use only the file name contained in the request line. But first a sanity check – we want to make sure the browser sent us a GET. The code to check for the GET looks like this: // The 1st 4 chars should be "GET " - let's see if they are. if ( strncmp( ip_input_buffer, "GET ", 4 ) != 0 ) { // An error occurred – it’s not a GET – print out a // nasty message and exit. exit(0); } I am assuming that you will be able to explain the workings of this code. Networks - Project 1

  21. Web Server in C: Part B • To extract the filename from the input string, you need to use a number of string manipulation functions available in C. These are all in the include file <string.h>. The ones that worked for me are • Strncmp • Strcpy • Strncat • Strchr • You may find others that better meet your needs, but if I were you, I’d start off by doing a “man strncmp”, etc. in order to understand these functions. I am assuming that you will be able to explain the workings of this code. Networks - Project 1

  22. Web Server in C: Part B • After you’ve extracted the filename from the browser string, print it out so we can see it – that way we know what the browser is asking for. Make sure that you preceed the filename with a “./” so that the file is required to exist in your current directory – otherwise the browser could be asking for any file in your entire directory structure. • So this line will look something like this: • printf( "The requested filename is %s\n", filename ); Networks - Project 1

  23. Web Server in C: Part B Now that we have the file name, we can open the file as the first step in sending it to the client. For that you can use an “fd = fopen( ??? )” command. Now your code follows one of two paths, depending if the file exists or not. If it does NOT exist, you must return a message saying so. If it does exist, then you want to send the contents of the file back to the browser. We’re using a simple function DoSend to make our life easier. This function is defined as follows: // /////////////////////////////////////////////////////////////////////// // DoSend - Send a packet to a TCP destination // call with DoSend( fdConn, TextString ); /////////////////////////////////////////////////////////////////////// void DoSend( int fdConn, char *Text ) { if ( send( fdConn, Text, strlen(Text), 0) <= 0 ) SysError( "Error on send of data in DoSend" ); } // End of DoSend Networks - Project 1

  24. Web Server in C: Part B • There are three parts to the response message: the status line, the response headers, and the entity body. So whether the file exists or not, these three types of strings must be defined and returned to the browser. • Let’s do the failure case first: • if ( fd == ??? ) // Error on File open • { • strcpy( StatusLine, “?????\r\n” ); • DoSend( fdConn, StatusLine ); • strcpy( ContentTypeLine, “????;\r\n\r\n"); • DoSend( fdConn, ContentTypeLine ); • strcpy( EntityBody,"<html><head><title>404 Not Found</title></head>"); • strcat( EntityBody, "<body><H1>Not Found</H1></body></html>\r\n"); • DoSend( fdConn, EntityBody ); • } • else • { • // Code for success • } • The \r\n is how the browser understands an end of line. Networks - Project 1

  25. Web Server in C: Part B When the file exists, we need to determine the file's MIME type and send the appropriate MIME-type specifier. We make this determination in a separate routine called contentType(), which returns a string that we can include in the content type line that we are constructing. Before we write the success case, let’s do a detour to talk about the routine contentType(). // /////////////////////////////////////////////////////////////////////// // ContentType - Determine the kind of file being asked for. // /////////////////////////////////////////////////////////////////////// char *ContentType( char *FileName ) { int FLength = strlen( FileName ); if ( ( strncmp( &(FileName[ FLength - 4 ]), ".htm", 4) == 0 ) || ( strncmp( &(FileName[ FLength - 5 ]), ".html", 5) == 0 ) ) return( "text/html" ); if ( ( strncmp( &(FileName[ FLength - 4 ]), ".ram", 4) == 0 ) || ( strncmp( &(FileName[ FLength - 3 ]), ".ra", 5) == 0 ) ) return( "audio/x-pn-realaudio" ); if ( ( you could have other kinds of audio, etc., etc. here ) ) return( “????" ); return( "application/octet-stream" ); // Default case } Networks - Project 1

  26. Web Server in C: Part B While we’re at it, let’s do one more detour to define a routine that reads data from the file and sends it out the network to the browser. We’ll call this routine SendFileData() and it will be invoked from within the success branch – we’ll use it when the file exists. Here’s that routine: // /////////////////////////////////////////////////////////////////////// // SendFileData - Send the data found in the file to the remote browser // fd is the descriptor for the file, fdConn is the descriptor // for the network connection. /////////////////////////////////////////////////////////////////////// void SendFileData( FILE *fd, int fdConn ) { char Buffer[BUFFERSIZE]; while( fgets( Buffer, sizeof(Buffer), fd ) != NULL ) DoSend( fdConn, Buffer ); fclose( fd ); } Networks - Project 1

  27. Web Server in C: Part B OK – now we’re ready to return and do the “else” portion of the if statement – the part where the file open has been successful. else // File Open OK { strcpy( StatusLine, “????\r\n" ); DoSend( fdConn, StatusLine ); strcpy( ContentTypeLine, "Content-Type: " ); strcat( ContentTypeLine, ContentType( filename ) ); strcat( ContentTypeLine, "\r\n\r\n" ); // Combines these 3 lines DoSend( fdConn, ContentTypeLine ); SendFileData( fd, fdConn ); // Send file to the client } Networks - Project 1

  28. Web Server in C: Part B There is a lot missing from this routine. For instance, nothing is returned for GIF or JPEG files. You may want to add the missing file types yourself, so that the components of your home page are sent with the content type correctly specified in the content type header line. For GIFs the MIME type is image/gif and for JPEGs it is image/jpeg. This completes the code for the second phase of development of your Web server. Try running the server from the directory where your home page is located, and try viewing your home page files with a browser. Remember to include a port specifier in the URL of your home page, so that your browser doesn't try to connect to the default port 80. When you connect to the running web server with the browser, examine the GET message requests that the web server receives from the browser. Networks - Project 1

  29. Appendix A This is the exact, working code for a multithreaded program. This program doesn’t do much, but that’s good because it will let you see what’s happening. Type it in and use it as the skeleton for the remainder of the project. // /////////////////////////////////////////////////////////////////////// // This is a simple program to test out the pthread package on Linux. // It can be built on a Linux machine with the command line // // gcc -lpthread -g -o proj2_thread_example proj2_thread_example.c // // /////////////////////////////////////////////////////////////////////// // #include <stdio.h> #include <pthread.h> #include <sys/resource.h> #include <asm/errno.h> int WorkThread( void * ); // Prototype unsigned int CreateAThread( void *, int *); // Prototype Networks - Project 1

  30. Appendix A Multi-threaded Example - Continued // /////////////////////////////////////////////////////////////////////// // This is the main() code - it is the original thread // /////////////////////////////////////////////////////////////////////// main() { int data = 3; unsigned int CurrentPriority, MyPid; unsigned int NewThreadID; // Get properties of this main thread MyPid = pthread_self(); CurrentPriority = getpriority( PRIO_PROCESS, 0 ); printf( "From Main: My ID is %ld and I have priority %d\n", MyPid, CurrentPriority ); // Create a new thread that will start executing at location WorkThread NewThreadID = CreateAThread( (void *)(*WorkThread), &data); printf( "From Main: The ID of the created thread is %ld\n", NewThreadID ); printf( "From Main: Data passed to the new thread is = %d\n\n", data ); sleep(4); // Wait for the new thread to finish exit(0); } // End of main Networks - Project 1

  31. Appendix A Multi-threaded Example - Continued // /////////////////////////////////////////////////////////////////////// // This is the code executed by the new thread // /////////////////////////////////////////////////////////////////////// int WorkThread( void *data ) { unsigned int CurrentPriority, MyPid; sleep(1); MyPid = pthread_self(); CurrentPriority = getpriority( PRIO_PROCESS, 0 ); printf( "Got to the new thread. My ID is %ld and I have priority %d\n", MyPid, CurrentPriority ); printf( "Data passed to the new thread is %d\n", (int *)data ); } // End of WorkThread Networks - Project 1

  32. Appendix A Multi-threaded Example - Continued // /////////////////////////////////////////////////////////////////////////////// // CreateAThread // Set up a new thread for the caller. We need to be passed here: // Arg1: The start address of the new thread // Arg2: The address of an int or structure containing data for the new thread // // We return the Thread Handle to the caller. // We print lots of errors if something goes wrong. But we return anyway // /////////////////////////////////////////////////////////////////////////////// unsigned int CreateAThread( void *ThreadStartAddress, int *data ) { int ReturnCode; pthread_t Thread; pthread_attr_t Attribute; ReturnCode = pthread_attr_init( &Attribute ); if ( ReturnCode != 0 ) printf( "Error in pthread_attr_init in CreateAThread\n" ); ReturnCode = pthread_attr_setdetachstate( &Attribute, PTHREAD_CREATE_JOINABLE ); if ( ReturnCode != 0 ) printf( "Error in pthread_attr_setdetachstate in CreateAThread\n" ); Networks - Project 1

  33. Appendix A Multi-threaded Example - Continued ReturnCode = pthread_create( &Thread, &Attribute, ThreadStartAddress, (void *)*data ); if ( ReturnCode == EINVAL ) /* Will return 0 if successful */ printf( "ERROR doing pthread_create - The Thread, attr or sched param is wrong\n"); if ( ReturnCode == EAGAIN ) /* Will return 0 if successful */ printf( "ERROR doing pthread_create - Resources not available\n"); if ( ReturnCode == EPERM ) /* Will return 0 if successful */ printf( "ERROR doing pthread_create - No privileges to do this sched type & prior.\n"); ReturnCode = pthread_attr_destroy( &Attribute ); if ( ReturnCode ) /* Will return 0 if successful */ printf( "Error in pthread_mutexattr_destroy in CreateAThread\n" ); return( (unsigned int)Thread ); } // End of CreateAThread Networks - Project 1

  34. Appendix B This is a simple web browser. It doesn’t display beautifully, but it DOES produce a textual output of what a web server sends back. You may find this very useful for debugging your server. /****************************************************************************** proj1_simple_browser.c This program does the simplest possible "GET /XXX HTTP/1.0/n/n" to a port that you specify. After doing the send to a web server, it simply prints out whatever that server sends back. This can be VERY useful for debugging. You can use port 80 to get to an apache web server, or some other port number to test your own server. Compile with: gcc -o proj1_simple_browser -g proj1_simple_browser.c ******************************************************************************/ #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> #define TRUE 1 #define FALSE 0 #define BUFFER_SIZE 2000 void SysError( char * ); Networks - Project 1

  35. Appendix B Simple Web Browser - Continued main ( int argc, char *argv[] ) { int family = AF_INET; // The default for most cases int type = SOCK_STREAM;// it's a TCP connection in_port_t port; struct sockaddr_in sa; int lsa = sizeof(sa); int fdListen, fdConn, fd; char ip_input_buffer[BUFFER_SIZE]; char ip_output_buffer[BUFFER_SIZE]; if ( argc < 2 ) { printf( "The program expects one argument\n" ); printf( "proj1_simple_browser <port number>\n" ); exit(0); } port = atoi(argv[1]); if ((fd = socket (family, type, 0)) < 0) SysError ("Error on socket"); sa.sin_family = family; sa.sin_port = htons(port); // client & server see same port sa.sin_addr.s_addr = htonl(INADDR_ANY); // the kernel assigns the IP addr Networks - Project 1

  36. Appendix B Simple Web Browser - Continued if (connect(fd, (struct sockaddr *)&sa, sizeof(sa) ) ) SysError ("Error on connect"); bzero( ip_output_buffer, sizeof( ip_output_buffer )); strcpy( ip_output_buffer, "GET /XYZZYxyzzy HTTP/1.0\n\n" ); if ( send( fd, ip_output_buffer, strlen(ip_output_buffer) + 1, 0 ) <= 0 ) SysError( "Error on send" ); bzero( ip_input_buffer, sizeof(ip_input_buffer) ); while(TRUE) { if ( recv( fd, ip_input_buffer, sizeof(ip_input_buffer) - 2, 0 ) <= 0 ) SysError( "Error on recv" ); printf( "%s", ip_input_buffer ); } } /* End of main */ void SysError( char *string ) { printf( "Error found: String given is --> %s\n", string ); exit(0); } Networks - Project 1

  37. Evaluation Your Name: ____________________________________________________ Here’s what you should be able to do for your project: • Be able to explain what your code is doing. For instance, how does this work? There’s lots of other places we could look also. • How did you modify DoSend in order to • Send binary data? • Can you send gif’s and jpeg’s? • Can you send and hear audio files? • Can you send VERY LARGE files? I will put a link in your directory to a file that you can send – characteristics unknown to you. • Can you handle a default where the user doesn’t specify a file but you go to index.html? • What do you do about favicon.ico? • Is your code multithreaded? • More questions? // The 1st 4 chars should be "GET " - let's see if they are. if ( strncmp( ip_input_buffer, "GET ", 4 ) != 0 ) { // An error occurred – it’s not a GET – print out a // nasty message and exit. exit(0); } How do the various string compare functions work? Networks - Project 1

More Related