This lab is much shorter than the other labs to give you the opportunity to prepare for your second checkpoint during the lab this week. Keep in mind that this content will be very relevant for your second assignment, so remember to come back to it later.

Outline#

In this week’s lab, you will:

  • Learn the system calls for network programming in Linux
  • Learn to use a networking API for performing client/server transactions
  • Hack an echo client-server application to gain practical experience with writing network applications
  • Set up and run and modify a tiny web server

Introduction#

We will look at two network application today that are based on the canonical client-server model. Recall from the lectures that clients and servers use the sockets API for establishing a connection. Once a connection is established they perform transactions by sending and receiving messages using a file descriptor.

The client and server both use the socket() system call. The client further uses the connect() system call for connection with the client. The server uses the bind(), listen(), and accept() system calls for listening to and accepting connections from clients. Refresh your knowledge of a typical client and server workflow in socket-based communication.

In this tutorial, we provide you with existing code for two network applications. These applications make use of wrappers on top of the systems calls for socket-based communication. We first want you to be comfortable with the API the application use.

In the lectures you have seen similar examples of networking code utilising the csapp library. In the lab8 directory we have provided you with a subset of this code that is relevant for the exercises this week. If desired, you can access the full csapp.c and csapp.h files.

Open the lab directory and investigate the code for open_clientfd() and open_listenfd() in network_utils.c. Make sure you have a basic idea of what these functions are trying to accomplish and how to use them in a network application.

Exercise 1: Echo Client/Server Application#

An echo client-server is an application that allows a client and a server to connect so a client can send a message to the server and the server can receive the message and send, or echo, it back to the client.

You are given the code for the client side in the echoclient.c file. The program receives a host name and port number as arguments, which it will use to open a connection. If a connection is successful it will then read lines from standard input using the getline function. Each line will be sent to the server using rio_writen. The response it receives from the server will then be printed to stdout.

If you’re not familiar with getline, remember to read the manual page by running the command man getline in your terminal.

You are also given the unfinished code for the server side in echoserver.c. It takes a port number as an argument, which it uses to open a listening socket. The server waits for connections using the accept function. When a client connects, it will first print out the hostname and port number the client has connected to.

Your task is to complete the echo function in echoserver.c so that it will read data sent by the client (using the connfd file descriptor) and send it back to the client.

Complete the echo function in echoserver.c.

Testing the Echo Client/Server Application#

First, let’s make sure the echo client and server can communicate properly on your local machine.

  • Start the echoserver in a terminal using any port that works for you. Avoid popular ports already taken (e.g. 25 or 80). We recommend using a port number > 1023.
  • Start echoclient in a separate terminal. Make sure you set the hostname argument to “localhost” and use the same port number as you did to launch echoserver.
  • Make sure (by observing the messages printed on the screen) that the client-server connection is established.
  • Type a message on the client side and make sure the message is echoed back by the server.

Push your changes to echoserver.c to GitLab. The CI will run a simple test by launching the server as a background process and attempt to initiate a connection to it using echoclient.

Exercise 2: Networking Questions#

Rather than more coding practice, this exercise will require you to think about questions regarding networking and the sockets API.

Is it possible to modify the echo server to send the clients IP address and port number to the client before echoing any messages? Identify the relevant code on the server side that will need to be changed.

Servers are designed to run for a long time without stopping. Therefore, they need to provide good service to all their clients regardless of client’s actions. Examine the echo client and server code and list anything you can think of that a client might do to cause the server to provide poor service to other clients. Suggest improvements to fix the problems you identify.

Once you have determined a way for a client to cause the server to provide poor service to other clients, test it on your implementation.

Why does the socket interface use listening and connected sockets to serve client requests? What would be wrong with having a server create a socket, set it up using bind() and listen(), wait for a connection, send and receive through that socket, and then when it is finished, close it and repeat the process?

Discuss your answers with a tutor or your fellow students.

Exercise 3: Echo Server With Metadata#

Your next exercise is to modify the echo server so that it sends the number of bytes it received from a client before echoing the response. For example, if a client sends the following:

./echoclient 127.0.0.1 1234
Hello, World!

The server should respond with the following:

Received 14 Bytes: Hello, World!

Copy across your code from echoserver.c to echoserver-metadata.c and modify the implementation so that it will send the size of the message before echoing the message.

Exercise 4: Tiny Web Server#

Web clients and servers interact using an application-level protocol called HTTP or hypertext transfer protocol. HTTP operates on top of the TCP/IP stack. HTTP works as follows. A web client (browser) opens an internet connection to a server and requests content. The web server responds with the requested content and then closes the connection. The browser displays the content on the screen. Web content is written in a language called hypertext markup language or HTML. Note the distinction between the protocol (used for communication and to request content and respond to content) and the language for displaying content.

The lab code repository includes a tiny web server. Open the file and inspect the code. Make sure you have a full understanding of what the key functions in the tiny web server are trying to accomplish. In particular, focus on the handle_client, serve_static and serve_dynamic functions.

Let’s make sure the web server works properly on your local machine.

  • Compile tiny by running the command make tiny.
  • Start tiny by running the executable and using a port number of your choice in a terminal, similar to the echo server.
  • From your web browser type localhost:port# to point the browser (client) to the webpage tiny (server) is serving. This will display the contents of the home.html file present in your directory.
  • Inspect the output from tiny in the terminal and make sure a connection is established and a transaction took place.

Exercise 5: Dynamic Content#

The tiny web server is able to serve dynamically generated content as well as static content.

Compile the adder program by running make adder and launch the tiny web server again. Observe what happens when you visit a url of the form localhost:PORT_NUM/cgi-bin/adder?N&M (where PORT_NUM is the port number the server is running on, and N/M are integers). Can you identify what the server uses to determine a dynamic request is being made, and how it runs the adder program to retrieve a the result?

You may find reviewing Lab 4 useful for understanding this code.

Using adder.c as a template, write another program sum_range.c that is invoked by visiting the URI /cgi-bin/sum_range?N&M&S (where N, M and S are integers). Given N and M, it should produce a HTML page that presents the result of summing all integers in the range N to M inclusive, with a step count of S.

You should be able to complete this task in such a way that requires no modifications to be made to tiny.c.

You should also endeavour to make your program as robust to “bad input” as possible. For example, how will your code handle a request for a step size of 0?

bars search times