Python Socket Programming and CRC Implementation Techniques
Python Networking and Data Integrity Techniques
This document provides practical Python implementations for fundamental networking tasks using the socket module, alongside a crucial data integrity mechanism: Cyclic Redundancy Check (CRC).
1. Building a Basic HTTP Client
Downloading a Webpage via TCP Socket
This function demonstrates how to manually establish a TCP connection to a host on port 80 and send a raw HTTP GET request to retrieve content.
import socket
def download_webpage(host, path="/"):
# Create a TCP socket (IPv4, Stream)
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to the host (HTTP port 80)
client_socket.connect((host, 80))
# Send an HTTP GET request
request = f"GET {path} HTTP/1.1\r\nHost: {host}\r\nConnection: close\r\n\r\n"
client_socket.send(request.encode())
# Receive the response from the server
response = b""
while True:
part = client_socket.recv(4096)
if not part:
break
response += part
# Close the socket
client_socket.close()
# Decode and return the response (ignoring potential errors)
return response.decode(errors="ignore")
# Example usage
host = "google.com"
page = download_webpage(host)
print(page)2. Implementing TCP Client-Server Communication
The following examples illustrate the fundamental setup for a local TCP server listening on port 8080 and a corresponding client that connects and exchanges messages.
TCP Server Setup
The server binds to an address and port, listens for connections, accepts them, receives data, sends a response, and closes the client connection.
import socket
def start_server():
# Create a socket object
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to an address and port
server_socket.bind(('localhost', 8080))
# Listen for incoming connections (max 5 connections queued)
server_socket.listen(5)
print("Server is listening on port 8080...")
while True:
# Accept a new connection
client_socket, client_address = server_socket.accept()
print(f"Connection from {client_address} has been established.")
# Receive data from the client
data = client_socket.recv(1024).decode('utf-8')
print(f"Received from client: {data}")
# Send a response back to the client
response = f"Server received: {data}"
client_socket.send(response.encode('utf-8'))
# Close the client socket
client_socket.close()
# start_server()TCP Client Implementation
The client connects to the specified server address, sends a message, waits for a response, and then closes the connection.
import socket
def start_client():
# Create a socket object
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to the server
client_socket.connect(('localhost', 8080))
# Send a message to the server
message = "Hello, Server!"
client_socket.send(message.encode('utf-8'))
# Receive a response from the server
response = client_socket.recv(1024).decode('utf-8')
print(f"Server response: {response}")
# Close the socket
client_socket.close()
# start_client()3. Cyclic Redundancy Check (CRC) Implementation
CRC is an error-detecting code used to verify data integrity during transmission. This implementation uses Modulo-2 division on binary strings.
Core CRC Functions for Data Integrity
The implementation relies on three core functions: xor for bitwise comparison, mod2div for the division process, and encode_data/decode_data for handling the data frame.
def xor(a, b):
"""Performs XOR operation on two binary strings of equal length."""
result = []
for i in range(len(a)):
result.append('0' if a[i] == b[i] else '1')
return "".join(result)
def mod2div(dividend, divisor):
"""Performs Modulo-2 division."""
N = len(divisor)
tmp = dividend[:N]
i = N
while i < len(dividend):
if tmp[0] == '1':
# XOR with divisor
tmp = xor(divisor, tmp) + dividend[i]
else:
# XOR with zero string
tmp = xor('0' * N, tmp) + dividend[i]
# Remove the leading bit
tmp = tmp[1:]
i += 1
# Final XOR operation to get the remainder
if tmp[0] == '1':
tmp = xor(divisor, tmp)
else:
tmp = xor('0' * N, tmp)
# Return the remainder (excluding the leading bit)
return tmp[1:]
def encode_data(data, key):
"""Encodes data using CRC by appending the remainder."""
N = len(key)
# Append N-1 zeros to the data
appended_data = data + '0' * (N - 1)
# Calculate remainder
remainder = mod2div(appended_data, key)
# The codeword is the original data plus the remainder
codeword = data + remainder
return codeword
def decode_data(data, key):
"""Decodes data and returns the remainder for error checking."""
remainder = mod2div(data, key)
return remainderExample Usage and Error Detection
This example demonstrates encoding a binary string and then checking the resulting codeword for errors upon reception.
if __name__ == "__main__":
# Example data to be transmitted
data = "1011001" # Binary data
key = "1101" # Divisor (CRC key)
print("Original Data:", data)
# Sender side: encoding
codeword = encode_data(data, key)
print("Encoded Data (Codeword):", codeword)
# Receiver side: decoding
received_data = codeword
# In a real scenario, 'received_data' might be corrupted
remainder = decode_data(received_data, key)
# Check if there is an error (remainder should be all zeros if no error)
print(f"Calculated Remainder: {remainder}")
if "1" in remainder:
print("Error detected in received data.")
else:
print("No error detected in received data.")