Lab 3: Python SocketsWinter 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 project 3. You will write a script that connects to a server, answers a few addition questions, then gets a secret code.

Useful Links

Setup

If you haven’t already, follow our Docker guide to learn how to set up Docker on your computer. You’ve probably already done this for previous labs and projects.

To get the code for this lab, create a repo using the GitHub template. Make sure to make this repo private. Clone the repo onto your system, then open it in VS Code. If you successfully set up Docker, you should be greeted with a pop-up in the bottom right asking you to reopen the directory in the development container; do so now! After some time taken to build the container, you should be greeted with the lab file in a directory and a terminal connected to the container (as shown in the Docker guide). If you’re having trouble at this point, please come to office hours or put up a post on Piazza describing in as much detail as possible what is going wrong—having a working Docker installation is essential for the course (which is why we’re making sure that it works in this lab!).

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

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. 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 it 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 lab3.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 covert into two integers. Add these integers together, then convert the sum into 4 bytes (using big-endianess).

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 exact 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:

  • lab3.py