Programming lesson
TCP Reno Congestion Control and Simulation: A Step-by-Step Guide
Learn TCP Reno congestion control with a detailed example, including slow start, congestion avoidance, and how to simulate token bucket and multi-thread servers. Perfect for COMP 5416 students.
Understanding TCP Reno with a Practical Example
TCP Reno is one of the most widely used congestion control algorithms. In this lesson, we'll walk through a typical assignment scenario involving TCP Reno and token bucket simulation. We'll also touch on multi-thread server implementation and BER vs SNR analysis. Let's start with a concrete network setup.
Network Setup and Parameters
Consider a path from node A to node E passing through B, C, and D. Each link has a bit rate of 1 Mbit/sec and a one-way propagation delay of 4 ms. The maximum packet size is 500 Bytes. We need to transmit 100 + s packets, where s is the last two digits of your student number. For example, if s = 45, we send 145 packets. The initial slow start threshold (ssthresh) is 8 segment sizes, i.e., 8 × 500 = 4000 Bytes. No packets are lost, and ACKs are negligible.
TCP Reno Phases
TCP Reno operates in two main phases: slow start and congestion avoidance. During slow start, the congestion window (cwnd) increases exponentially (doubles every RTT). Once cwnd reaches ssthresh, TCP enters congestion avoidance, where cwnd increases linearly (by 1 MSS per RTT). In this assignment, since no loss occurs, TCP Reno will stay in congestion avoidance after reaching ssthresh.
Calculating Transmission Time
First, compute the round-trip time (RTT). The one-way propagation delay is 4 ms per link, so total propagation delay = 4 links × 4 ms = 16 ms. The transmission delay for one packet of 500 Bytes at 1 Mbit/sec: 500 × 8 bits / 1,000,000 bps = 0.004 sec = 4 ms. So RTT = 2 × (propagation + transmission) = 2 × (16 + 4) = 40 ms.
Now, simulate the window evolution. Start with cwnd = 1 MSS (500 Bytes). In slow start, cwnd doubles each RTT until it reaches ssthresh = 8 MSS. That takes log2(8) = 3 RTTs. After that, congestion avoidance: each RTT, cwnd increases by 1 MSS. We need to transmit 145 packets. Let's sum the packets sent each RTT. Slow start: RTT1: 1, RTT2: 2, RTT3: 4, RTT4: 8 (now at ssthresh). After RTT4, cwnd = 8. Congestion avoidance: RTT5: 9, RTT6: 10, ... Continue until total packets >= 145. The total time is number of RTTs × 40 ms. For 145 packets, you'll need about 17 RTTs, so total time ≈ 680 ms. (Exact calculation depends on s.)
Token Bucket Simulation
Token bucket is a traffic shaping mechanism. In this assignment, you simulate a bucket with capacity x tokens, where x = 3 + floor(s/2). For s = 45, x = 3 + 22 = 25. Packet arrivals follow a Poisson process with λ = 1 packet/sec, token arrivals are deterministic with rate μ = 1.25 tokens/sec. The bucket can hold up to x tokens, and the queue is infinite.
System States
States are integers: positive values indicate number of packets in the buffer, negative values indicate number of tokens in the bucket (e.g., -x means x tokens), and 0 means empty. You need to find the stationary distribution via simulation. Use discrete-event simulation: generate packet arrival times (exponential inter-arrival) and token arrival times (constant inter-arrival = 0.8 sec). At each event, update the state. Run for a long time (e.g., 10^6 seconds) and record the fraction of time spent in each state.
Conditional Distributions
To find the conditional distribution upon packet arrival, record the system state just before each packet arrival. Similarly for token arrivals. The mean waiting time in the buffer is the average time a packet spends in queue before being served. You can compute this using Little's Law: mean queue length / arrival rate. Or directly measure from simulation.
Token Drop Probability
A token is dropped if it arrives when the bucket is full (state = -x). Count the number of token arrivals that find the bucket full and divide by total token arrivals.
Multi-Thread Server Implementation
Building a multi-thread TCP server in Python is essential for handling multiple clients concurrently. The key is to use _thread.start_new_thread() or the higher-level threading module. For each new client connection, spawn a new thread to handle communication. This allows the server to accept new clients while existing connections are being served.
Server Code Structure
import socket
import _thread
def handle_client(conn, addr):
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data:
break
# Process data (e.g., receive image)
conn.sendall(data) # echo back
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('localhost', 12011))
s.listen()
while True:
conn, addr = s.accept()
_thread.start_new_thread(handle_client, (conn, addr))Testing with Multiple Clients
You can test using the provided client code (Week 8 lab). Run three clients simultaneously, each sending an image file. Use Wireshark to capture packets on the server side. Filter by TCP port 12011. Observe that data transfers overlap in time, proving concurrency. Plot throughput vs. time for each connection: you should see positive throughput for all three during the same period.
BER vs SNR with BPSK and 4QAM
In wireless communications, Bit Error Rate (BER) vs Signal-to-Noise Ratio (SNR) curves characterize modulation schemes. For BPSK, the theoretical BER is Q(sqrt(2*SNR)), where Q is the tail probability of the standard normal distribution. For 4QAM, BER = Q(sqrt(SNR)) (since each dimension carries one bit).
Simulation in Python
Generate random bits, map to symbols, add Gaussian noise with variance corresponding to SNR (in dB: SNR_linear = 10^(SNR_dB/10)). Decode by comparing received signal to decision threshold. Count errors for each SNR value (0,5,10,15,20,25 dB). Plot the results. For BPSK, use 1 million bits for accuracy.
Example Code Snippet
import numpy as np
import matplotlib.pyplot as plt
def ber_bpsk(snr_db):
snr = 10**(snr_db/10)
noise_std = np.sqrt(1/snr)
bits = np.random.randint(0,2,1000000)
symbols = 2*bits - 1
noise = noise_std * np.random.randn(len(symbols))
received = symbols + noise
decoded = (received >= 0).astype(int)
return np.mean(bits != decoded)Repeat for 4QAM using two dimensions.
Conclusion
This lesson covered key concepts from COMP 5416 Assignment 2: TCP Reno transmission time calculation, token bucket simulation, multi-thread server implementation, and BER vs SNR analysis. By understanding these examples, you can tackle similar problems in networking and communication. Remember to simulate carefully and verify your results.