Paper 2 Computer Networks Answers
These answers correspond to Paper 2 Computer Networks Drills.
Verification note: every Python code block in this answer file has been executed locally.
Answer 1: Encode Decode
Model answer:
def round_trip(text):
data = text.encode("utf-8")
decoded = data.decode("utf-8")
return decoded
print(round_trip("hello"))
print(round_trip("café"))Expected output:
hello
caféMark points:
- uses
.encode("utf-8")on the input string; - stores or passes the encoded byte sequence correctly;
- uses
.decode("utf-8")on the bytes; - returns the decoded string and produces the expected output for both ASCII and non-ASCII text.
Common weak answer:
- returning the bytes object instead of decoding it back into a string.
Answer 2: Simple Client
Model answer with a local one-shot test server:
import socket
import threading
def start_ack_server():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("127.0.0.1", 0))
server.listen(1)
port = server.getsockname()[1]
def serve_once():
conn, _ = server.accept()
data = b""
while b"\n" not in data:
chunk = conn.recv(1024)
if chunk == b"":
break
data += chunk
message = data.decode("utf-8").strip()
conn.sendall(("ACK:" + message + "\n").encode("utf-8"))
conn.close()
server.close()
thread = threading.Thread(target=serve_once)
thread.start()
return port, thread
def send_message(host, port, message):
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((host, port))
client.sendall((message + "\n").encode("utf-8"))
data = b""
while b"\n" not in data:
chunk = client.recv(1024)
if chunk == b"":
break
data += chunk
client.close()
return data.decode("utf-8").strip()
port, thread = start_ack_server()
print(send_message("127.0.0.1", port, "HELLO"))
thread.join()Expected output:
ACK:HELLOMark points:
- creates a TCP socket using
socket.AF_INETandsocket.SOCK_STREAM, or an equivalent TCP socket call; - connects to the given
(host, port)tuple; - encodes the outgoing message with a newline delimiter before sending;
- uses
sendallor otherwise ensures the full message is sent; - receives until the newline-delimited server reply is complete;
- decodes the reply from bytes to string;
- closes the client socket;
- returns the decoded reply shown by the test output.
Common weak answer:
- sending a Python string directly with
sendall(message). Socket send operations require bytes.
Answer 3: Simple Server
Model answer with a local client test:
import socket
import threading
import time
def run_once_server(host, port):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port))
server.listen(1)
conn, _ = server.accept()
data = b""
while b"\n" not in data:
chunk = conn.recv(1024)
if chunk == b"":
break
data += chunk
message = data.decode("utf-8").strip()
conn.sendall(("RECEIVED:" + message + "\n").encode("utf-8"))
conn.close()
server.close()
temporary = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
temporary.bind(("127.0.0.1", 0))
port = temporary.getsockname()[1]
temporary.close()
thread = threading.Thread(target=run_once_server, args=("127.0.0.1", port))
thread.start()
time.sleep(0.05)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("127.0.0.1", port))
client.sendall("PING\n".encode("utf-8"))
data = b""
while b"\n" not in data:
chunk = client.recv(1024)
if chunk == b"":
break
data += chunk
print(data.decode("utf-8").strip())
client.close()
thread.join()Expected output:
RECEIVED:PINGMark points:
- creates a TCP server socket;
- binds the socket to a host and port;
- listens for incoming connections;
- accepts one client connection;
- receives bytes until the newline delimiter is found;
- decodes the complete request line;
- forms the response
"RECEIVED:" + message; - encodes and sends the response with a newline delimiter;
- closes both the connection socket and the server socket;
- test client sends
"PING\n"and the output matchesRECEIVED:PING.
Common weak answer:
- calling
recvon the server socket instead of the accepted connection socket.
Answer 4: Echo Server Logic
Model answer:
def echo_messages(messages):
replies = []
for message in messages:
if message == "QUIT":
break
replies.append("ECHO:" + message)
return replies
print(echo_messages(["red", "blue", "QUIT", "green"]))Expected output:
['ECHO:red', 'ECHO:blue']Mark points:
- initializes a list of replies;
- loops through the input messages in order;
- checks for
"QUIT"; - stops immediately when
"QUIT"is reached; - does not echo
"QUIT"; - does not process later messages after
"QUIT"; - prefixes ordinary messages with
"ECHO:"; - appends each echo reply to the list;
- returns the reply list;
- preserves the original message order before
"QUIT"; - produces exactly two replies for the given test;
- matches the expected output.
Common weak answer:
- filtering out
"QUIT"but still processing"green". The protocol says"QUIT"ends the session.
Answer 5: Port Config
Model answer:
HOST = "127.0.0.1"
PORT = 5000
def endpoint():
return (HOST, PORT)
print(endpoint())Expected output:
('127.0.0.1', 5000)Mark points:
- defines
HOSTwith the given loopback address; - defines
PORTas integer5000; - returns the two values as a tuple in the correct order;
- test output matches the expected endpoint.
Common weak answer:
- storing the port as
"5000"when socket calls expect an integer port number.
Answer 6: Protocol Message
Model answer:
def parse_message(message):
parts = message.split(":")
if len(parts) != 2:
return None
command, id_text = parts
if not id_text.isdigit():
return None
return (command, int(id_text))
print(parse_message("GET:42"))
print(parse_message("BAD"))Expected output:
('GET', 42)
NoneMark points:
- splits the message using
":"; - rejects messages that do not have exactly two parts;
- separates the command from the ID text;
- validates that the ID is numeric;
- converts the ID to an integer;
- returns
Nonefor the malformed"BAD"input.
Common weak answer:
- assuming
message.split(":")[1]always exists. A malformed message should not crash the program.
Answer 7: DNS Lookup
Model answer:
dns = {
"school.test": "192.0.2.10",
"library.test": "192.0.2.20"
}
def lookup(domain):
if domain in dns:
return dns[domain]
return "NOT FOUND"
print(lookup("school.test"))
print(lookup("missing.test"))Expected output:
192.0.2.10
NOT FOUNDMark points:
- represents domain names as dictionary keys;
- represents IP addresses as dictionary values;
- checks or retrieves the requested domain;
- returns the correct IP for
"school.test"; - returns
"NOT FOUND"for a missing domain.
Common weak answer:
- looping through values rather than looking up by domain name. DNS resolution is naturally modelled as name-to-address lookup.
Answer 8: Packet Reassembly
Model answer:
fragments = [(3, "ORL"), (1, "HEL"), (4, "D"), (2, "LOW")]
def reassemble(fragments):
ordered = sorted(fragments)
payloads = []
for _, payload in ordered:
payloads.append(payload)
return "".join(payloads)
print(reassemble(fragments))Expected output:
HELLOWORLDMark points:
- treats each fragment as a sequence number plus payload;
- sorts fragments by sequence number;
- extracts payloads after sorting;
- joins payload strings without extra spaces;
- reconstructs
HELLOWORLD; - does not rely on the arrival order;
- handles all four fragments;
- prints the expected output.
Common weak answer:
- joining the fragments in their received order, which would produce
ORLHELDLOW.
Answer 9: Client Test
Model answer:
def expected_response(message):
if message == "PING":
return "PONG"
if message.startswith("GET:"):
item_id = message[4:]
return "ITEM " + item_id
return "ERROR"
print(expected_response("PING"))
print(expected_response("GET:42"))
print(expected_response("HELLO"))Expected output:
PONG
ITEM 42
ERRORMark points:
- handles the normal
PINGrequest; - handles a
GET:<id>request by extracting the ID; - returns
ERRORfor an invalid request; - test output includes all three expected responses.
Common weak answer:
- testing only the normal case. A useful client test includes an invalid request as well.
Answer 10: Connection Error
Model answer:
import socket
def safe_connect(host, port):
try:
client = socket.create_connection((host, port), timeout=0.1)
client.close()
return "CONNECTED"
except OSError:
return "CONNECTION FAILED"
print(safe_connect("127.0.0.1", 1))Expected output:
CONNECTION FAILEDMark points:
- attempts the connection using the supplied host and port;
- uses a short timeout so the program does not hang;
- closes the socket if the connection succeeds;
- catches connection-related
OSErrorexceptions; - returns a controlled failure message instead of crashing;
- produces the expected output for the closed local port test.
Common weak answer:
- catching every exception and hiding unrelated programming errors. It is better to catch the connection-related exception type expected here.