Lab 4: Python SocketsSpring 2024

This lab seeks to help introduce you to TCP sockets, and how to use them in Python since you will be doing this in the networking project. You will write a script that connects to a server, answers a few addition questions, and then gets a secret code.

Setup

For this lab and the corresponding project, you will be required to write your solutions inside the provided Docker container. It is capable of running all the programs needed and has been configured to automatically set up the required services that are essential to test your solutions for the project. However, if you haven’t set up the Docker environment yet, follow our Docker guide to learn how to set up Docker on your computer.

To get the starter code for this lab, follow the steps below:

  1. Create a repo using the GitHub template. Make sure to make this repo private.
  2. Clone the repo onto your system (you’ll need to supply your GT credentials for this), then open it in VS Code. Make sure all the Docker containers for previous labs and projects, including this project, are shut down before setting up the environment for the current lab
  3. If you successfully set up Docker, you should be greeted with a pop-up in the bottom right asking you to re-open the directory in the development container; do so now!
  4. It will take some time to build the container, and once done, you should be able to see the lab files in a directory and a terminal connected to the container (as shown in the Docker guide).

Git Guide: If you’re unfamiliar with using Git/GitHub, check out this guide to help you get started.

Background

You already have experience with HTTP, which is a protocol for communicating over the network. It is convenient, but it’s also quite limited. The only communication scheme it allows is for the client to send a complete message, and then for the server to respond with a complete message.

TCP is a lower-level protocol, which makes it a bit harder to work with, but a lot more flexible. At any moment, the client or the server can send the other a stream of bytes. This stream is guaranteed to arrive in order, but it may not arrive all at once. This allows the recipient to get started processing the data before the sender has even finished sending it.

Resources

Python Socket Basics

Tasks

Overview

You will write a Python script that interacts with a server over TCP. The server will ask your script a few simple addition questions, one at a time, and wait for your answers before sending the next one. If you answer them all correctly, it will give you a secret phrase that you will print out.

It may be helpful to reference the Python Socket Programming HOWTO guide and the Python socket module documentation while working on this lab.

Running the script

Your script should take 2 command line arguments, which tell your script how to locate the server. The first one is the hostname. The second one is the port number. When running your script locally, use mathserver and 8000. You have to be inside the Docker container in order to connect to the mathserver.

python3 lab4.py mathserver 8000

You can also run your script in the VS Code debugger.

Connecting to the Server

In order to use sockets in Python, you will have to import the socket module:

import socket

Construct a new socket:

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:

The socket will be automatically closed as soon as you leave the with-statement. Make sure that you only interact with sock inside the with-statement.

Then connect the socket to the server:

sock.connect((HOST, PORT))

Do not hardcode HOST and PORT. The Autograder will use different values than what you use in your Docker container.

Communicating with the Server

Questions & Answers

As soon as you connect to the server, it will send you your first addition question.

To receive the data it has sent you:

data = sock.recv(4096)

Reminder: TCP transfers data as a stream. This means that any “message” the server sends you isn’t guaranteed to arrive all at once. You may need to call sock.recv multiple times in order to get the full “message”.

Each time you call sock.recv, you’ll be reading new data. Make sure to save the data from each call so you can concatenate it all together.

The question will be formatted as the following 9 bytes:

+---+---------------------------+---------------------------+
| Q | 4-byte big-endian integer | 4-byte big-endian integer |
+---+---------------------------+---------------------------+

The Q byte indicates that this is a question. You will need to convert into two integers. Add these integers together, then convert the sum into 4 bytes (using big-endianness).

Now that you have your answer in the form of bytes, send it back to the server:

sock.sendall(answer)

If you get the answer wrong, the server will close the connection early.

This question-and-answer process will repeat a random number of times. Once it’s done, the server will send you a secret phrase instead of a question.

Secret Phrase

Receiving the secret phrase is exactly the same process as receiving a question:

data = sock.recv(4096)

The secret phrase will be formatted as the following 9 bytes:

+---+----------------------+
| S | 8-byte secret phrase |
+---+----------------------+

You can tell that this is a secret phrase and not a question because it begins with an S byte instead of a Q byte.

Print this 8-byte secret phrase.

Closing the Connection

If you put the socket inside a with-statement, it will automatically be closed as soon as you leave.

If you didn’t put the socket inside a with-statement, you can close it manually with:

sock.close()

Submission

Submit the following files to the Autograder by the deadline:

  • lab4.py