Computer Networks - PowerPoint PPT Presentation

1 / 37
About This Presentation
Title:

Computer Networks

Description:

For instance, nothing is returned for GIF or JPEG files. ... What do you do about favicon.ico? Is your code multithreaded? More questions? ... – PowerPoint PPT presentation

Number of Views:168
Avg rating:3.0/5.0
Slides: 38
Provided by: jb20
Category:

less

Transcript and Presenter's Notes

Title: Computer Networks


1
Computer Networks
  • Project 2
  • Prof. Jerry Breecher

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. Youll
    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.

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
    its 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 dont like these documents, there are
    plenty of other ones out on the web. Go wild!

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 peoples
    work.

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.
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.edu6789/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.
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 thats just been
accepted from the remote browser. See the
diagram on the next page to better understand
this.
8
Overview Of Operation
Web Browser
Your Web Server
Connect Send Receive
Accept( new_socket ) Create_thread
New Thread
Receive Send
9
Web Server in C Part A
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
include include include
include 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
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, well use port
6789.
// This is the main() code - it is the original
thread main() int port
6789 // Set the port number.
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, ???? )
12
Web Server in C Part A
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.
while(TRUE) // Do the accept fdconn
accept( fdListen, ???? ) out
CreateAThread( (void )(WorkThread), (void
)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.
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,
well be talking about what happens in the new
thread WorkThread.
14
Web Server in C Part A
So now we start talking about our new thread
WorkThread. Its easiest to think of this simply
as a subroutine. Its as if main is calling this
as a routine, except that its 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 whats 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
15
Web Server in C Part A
Now, let's develop the code within WorkThread. We
declare an input buffer to hold the data were
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_bufferBUFFERSIZE bzero(
ip_input_buffer, sizeof( ip_input_buffer ))
Then we get the clients 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 its
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 )
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 dont know
so we just keep reading until we dont get
anything more. When were done reading and
printing data, then simply close the connection
as shown.
close(???) // End of WorkThread
17
Web Server in C Part A
Thats all the code we write for Part A. Our web
server isnt serving yet all its doing is
printing out what the client hands it but
thats 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.edu6789/
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.
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 well 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.

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(
?? ) recv of data from browser\n" ) else
// This is where we go after a successful
receive.
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 its 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.
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 . 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, Id 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.
22
Web Server in C Part B
After youve 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 )
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. Were 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) "Error on send of data in DoSend" ) // End
of DoSend
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. Lets do the failure
case first if ( fd ??? )
// Error on File open strcpy( StatusLine,
?????\r\n ) DoSend( fdConn, StatusLine
) strcpy( ContentTypeLine, ????\r\n\r\n") DoSe
nd( fdConn, ContentTypeLine ) strcpy(
EntityBody,"404 Not
Found") strcat( EntityBody,
"Not Found\r\n") DoS
end( fdConn, EntityBody ) else //
Code for success The \r\n is how the
browser understands an end of line.
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, lets 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
26
Web Server in C Part B
While were at it, lets do one more detour to
define a routine that reads data from the file
and sends it out the network to the browser.
Well call this routine SendFileData() and
it will be invoked from within the success branch
well use it when the file exists. Heres 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
BufferBUFFERSIZE while( fgets( Buffer,
sizeof(Buffer), fd ) ! NULL ) DoSend(
fdConn, Buffer ) fclose( fd )
27
Web Server in C Part B
OK now were 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
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.
29
Appendix A
This is the exact, working code for a
multithreaded program. This program doesnt do
much, but thats good because it will let you see
whats 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
include include
include int
WorkThread( void ) //
Prototype unsigned int CreateAThread( void ,
int ) // Prototype
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
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
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"
)
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
34
Appendix B
This is a simple web browser. It doesnt 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 include
include def
ine TRUE 1 define
FALSE 0 define BUFFER_SIZE
2000 void SysError( char )
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_bufferBUFFER_SIZE
char ip_output_bufferBUFFER_SIZE
if ( argc program expects one argument\n" )
printf( "proj1_simple_browser \n"
) exit(0) port
atoi(argv1) if ((fd socket (family,
type, 0)) 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
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 ) 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 )
printf( "s", ip_input_buffer )
/ End of main
/ void SysError( char string )
printf( "Error found String given is --
s\n", string ) exit(0)
37
Evaluation
Your Name ______________________________________
______________ Heres 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? Theres lots of
    other places we could look also.
  • How did you modify DoSend in order to
  • Send binary data?
  • Can you send gifs and jpegs?
  • 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 doesnt
    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 its not a GET
print out a // nasty message and
exit. exit(0)
How do the various string compare functions work?
Write a Comment
User Comments (0)
About PowerShow.com