A secure, reliable group notification system built over SSL/TLS-encrypted TCP sockets. Designed as the Jackfruit Mini Project for the Computer Networks Lab at PES University.
The objective of this project is to design and implement a secure networked application using low-level socket programming. The system demonstrates:
- TCP + SSL/TLS encrypted communication for all data and control exchanges
- A custom binary protocol with sequence numbers, CRC32 checksums, and message framing
- Application-layer reliability on top of SSL/TCP: ACK tracking, retransmission, and duplicate detection
- Keep-Alive / Heartbeat for automatic detection and eviction of disconnected clients
- A best-effort UDP baseline for head-to-head performance comparison
- Automated testing under 0%β30% simulated packet loss with Matplotlib performance graphs
| Roll Number | Name | Responsibility |
|---|---|---|
| PES2UG24CS030 | Aditya Basavaraj Jambagi | Server, SSL setup, ACK/Retransmit logic |
| PES2UG24CS033 | Aditya Raj | Client, Protocol design, Heartbeat |
| PES2UG24CS044 | Aks Raj Singh | Testing framework, Performance metrics |
NOTIFICATION SERVER (server.py)
ββββββββββββββββββββββββββββββββββββββββββββββββ
β β
Port 5001 β ββββββββββββββββββββββββββββββββββββββββββ β
ββSSL/TCP Authβββββββ€ β accept_ssl_clients() thread β β
β (SUBSCRIBE only) β β β TLS 1.3 handshake (server.crt/.key) β β
β β β β Reads SUBSCRIBE + client's UDP port β β
β β β β Registers (IP, udp_port) in set β β
β β β β Closes SSL connection (one-shot) β β
β β ββββββββββββββββββββββββββββββββββββββββββ β
β β β
β Port 5000 β ββββββββββββββββββββββββββββββββββββββββββ β
βββUDP Dataββββββββββ€ β listen_udp() thread β β
(NOTIFY/ACK/ β β β Receives ACK, HEARTBEAT, UNSUBSCRIBEβ β
HEARTBEAT/ β ββββββββββββββββββββββββββββββββββββββββββ β
UNSUBSCRIBE) β β
β ββββββββββββββββββββββββββββββββββββββββββ β
β β retransmission_thread() β β
β β β Retransmits unACK'd UDP packets β β
β β β Evicts clients silent for 5s β β
β ββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββ¬βββββββββββββββββββββββββββββ
β
UDP broadcasts (NOTIFY) β all subscribers
βββββββββββββββ΄βββββββββββββββ
β β
ββββββββββββΌβββββββββββ βββββββββββββΌββββββββββ
β CLIENT A β β CLIENT B β
β (client.py) β β (client.py) β
β β β β
β 1. subscribe(): β β 1. subscribe(): β
β SSL/TCP to :5001 β β SSL/TCP to :5001 β
β sends UDP port β β sends UDP port β
β β closes SSL β β β closes SSL β
β β β β
β 2. listen() [UDP]: β β 2. listen() [UDP]: β
β recv NOTIFY β β recv NOTIFY β
β β send ACK (UDP) β β β send ACK (UDP) β
β β β β
β 3. heartbeat [UDP]: β β 3. heartbeat [UDP]: β
β ping every 2s β β ping every 2s β
ββββββββββββββββββββββββ βββββββββββββββββββββββ
Topology : Star (1 server β N clients, individual unicast sockets)
Auth : SSL/TLS (TLS 1.3) on port 5001 β SUBSCRIBE only (one-shot)
Data : UDP on port 5000 β NOTIFY, ACK, HEARTBEAT, UNSUBSCRIBE
Protocol : Custom binary packet [4B seq | 1B type | 2B len | 2B CRC32] + payload
Every message β whether a SUBSCRIBE, NOTIFY, ACK, HEARTBEAT, or UNSUBSCRIBE β uses
the same 9-byte binary header format defined in protocol.py:
0 4 5 7 9 9 + payload_len
βββββββββββββ¬βββ¬βββββββ¬βββββββ¬βββββββββββββββββββββ
β Seq Num βTyβ Len β CRC β Payload β
β (4 bytes) βpeβ(2 B) β(2 B) β (variable length) β
β uint32 β(1βuint16βuint16β UTF-8 string β
βββββββββββββ΄βββ΄βββββββ΄βββββββ΄βββββββββββββββββββββ
- Seq Num: Monotonically increasing ID for reliable delivery tracking
- Type:
1=SUBSCRIBE,2=NOTIFY,3=ACK,4=UNSUBSCRIBE,5=HEARTBEAT - Len: Payload byte count (used by TCP framing helpers)
- CRC: 16-bit CRC32 checksum for corruption detection
- Payload: For NOTIFY:
"timestamp|message"(timestamp used for latency calculation)
All communication between the server and clients is encrypted using TLS 1.3
via Python's built-in ssl module.
| File | Description |
|---|---|
server.crt |
X.509 self-signed public certificate (shared) |
server.key |
RSA-2048 private key (kept on server only) |
If the certificates expire or are missing, regenerate them with:
openssl req -x509 -newkey rsa:2048 \
-keyout server.key \
-out server.crt \
-days 365 \
-nodes \
-subj '/CN=localhost'Note: The
-nodesflag skips passphrase encryption on the private key (required for non-interactive server startup). For production environments, use a CA-signed certificate and enablessl.CERT_REQUIREDon the client.
| Requirement | Version / Notes |
|---|---|
| Python | 3.8 or higher |
ssl |
Built into Python standard library |
socket |
Built into Python standard library |
struct |
Built into Python standard library |
zlib |
Built into Python standard library |
matplotlib |
For performance graph generation |
Install matplotlib:
pip install matplotlibVerify SSL certificate files exist before starting the server:
ls -lh server.crt server.keyThis method proves the entire Hybrid Architecture (TLS + UDP) works perfectly without fighting university firewalls or mobile hotspot AP isolation.
- Open Terminal 1 (The Server)
python3 server.py
- Open Terminal 2 (Client 1)
python3 client.py
- Open Terminal 3 (Client 2)
python3 client.py
- Test the Broadcast
Go back to Terminal 1, type
Hello world!and press Enter. You will instantly see the UDP broadcast hit both clients, and see the ACKs returned to the server.
Note: This will NOT work on an iPhone/Android Mobile Hotspot or University Wi-Fi due to "Client AP Isolation" hardware firewalls dropping peer-to-peer UDP packets. You MUST be connected to a normal Home Router.
-
On Laptop 1 (The Mac/Server): Find your IP Address:
ipconfig getifaddr en0
(Let's assume it prints
192.168.1.5)Start the server:
python3 server.py
-
On Laptop 2 (The Windows/Friend's PC): Ensure they have the latest code, then run the client by typing the Mac's IP address directly in the command:
python client.py 192.168.1.5
-
Test the Broadcast: Type a message on the Mac server, and it will instantly pop up on the Windows laptop securely!
Runs all tests (0%β30% loss) for both systems and saves the graph:
python3 test_system.pyOutput: performance_results.png with 4 comparison panels.
SSL/TLS was designed specifically for stream-oriented (TCP) sockets. While DTLS
(Datagram TLS) exists for UDP, Python's ssl module does not natively support it.
Switching to TCP+SSL gives us full encryption with standard library support.
TCP guarantees bytes arrive at the OS receive buffer. Our application-level ACKs provide a stronger guarantee: the client application processed the notification. This semantic difference is important for notification systems where silent drops (app crashed after receive but before processing) would otherwise go undetected.
Unlike multicast (which has router support requirements), unicast over individual SSL sockets gives us per-client delivery tracking. We know exactly which client received which message and can retransmit selectively.
Tests conducted with 3 clients, 5 notifications per run, at four loss levels:
| Metric | System | 0% Loss | 10% Loss | 20% Loss | 30% Loss |
|---|---|---|---|---|---|
| Delivery Rate | Reliable SSL | ~100% | ~100% | ~100% | ~90-100% |
| Delivery Rate | Plain UDP | ~100% | ~80% | ~65% | ~50% |
| Avg Latency | Reliable SSL | Low | Moderate | Moderate | High |
| Avg Latency | Plain UDP | Low | Low | Low | Low* |
| Retransmissions | Reliable SSL | 0 | Low | Moderate | High |
*Plain UDP latency appears lower at high loss because undelivered messages are simply not counted β the sample set is smaller and biased toward fast arrivals.
At 30% packet loss, Plain UDP delivers only ~50% of messages. Our Reliable SSL system maintains 90β100% delivery β at the cost of higher latency due to retransmission wait times. This is the classic reliability vs. latency tradeoff in network systems design.
| File | Description |
|---|---|
protocol.py |
Custom binary packet format, CRC checksum, TCP framing helpers |
server.py |
SSL/TCP notification server with ACK, retransmit, heartbeat |
client.py |
SSL/TCP subscriber client with listener, heartbeat, latency track |
plain_udp.py |
Best-effort UDP baseline (no SSL, no ACKs, no retransmission) |
test_system.py |
Automated testing framework β 4 metrics, 4 loss levels, 4 graphs |
server.crt |
SSL public certificate (X.509, self-signed, RSA-2048) |
server.key |
SSL private key (RSA-2048, not encrypted, lab use only) |
performance_results.png |
Output graph from the last test run |