Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Building TCP Socket Servers with File Logging and XOR Encryption in Python

Tech May 19 1

Network communication in Python relies heavily on the socket library, which provides low-level access to the transport layer. This technical overview demonstrates establishing a TCP connection between a server and a client, extending functionality with file logging, and implementing basic data encryption.

Basic Server-Client Architecture

The foundation involves creating a server that binds to a specific interface and port, listening for incoming connections, and a client that initiates the handshake. The following implementation uses IPv4 and TCP (SOCK_STREAM).

Server Implementation

The server initializes a socket, binds to localhost on port 5050, and enters a loop to handle incoming data. Connection management is handled via try...finally blocks to ensure resources are released.

import socket

def start_server(host='127.0.0.1', port=5050):
    listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        listener.bind((host, port))
        listener.listen(1)
        print(f'Server listening on {host}:{port}')
        
        conn, addr = listener.accept()
        with conn:
            print(f'Connected by {addr}')
            while True:
                incoming = conn.recv(1024).decode('utf-8')
                if not incoming:
                    break
                print(f'Received: {incoming}')
                
                reply = input('Enter response: ')
                conn.sendall(reply.encode('utf-8'))
                
                if input('Continue? (y/n): ').lower() == 'n':
                    break
    finally:
        listener.close()

if __name__ == '__main__':
    start_server()

Client Implementation

The client connects to the server's address and engages in a send-receive loop. It encodes user input before transmission and decodes incoming byte streams.

import socket

def start_client(host='127.0.0.1', port=5050):
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        client.connect((host, port))
        print('Connected to server')
        
        while True:
            msg = input('Message to server: ')
            client.sendall(msg.encode('utf-8'))
            
            data = client.recv(1024).decode('utf-8')
            if not data:
                break
            print(f'Server reply: {data}')
            
            if input('Continue? (y/n): ').lower() == 'n':
                break
    finally:
        client.close()

if __name__ == '__main__':
    start_client()

Integrating File I/O

To persist communication history, both endpoints can log transactions to local files. Using context managers (with statement) ensures files are properly closed after writing.

Server-Side Logging

The server appends received messages and sent responses to server_log.txt.

import socket

def run_logged_server(host='127.0.0.1', port=5050):
    srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    srv.bind((host, port))
    srv.listen(1)
    conn, addr = srv.accept()
    
    with conn, open('server_log.txt', 'a', encoding='utf-8') as log:
        while True:
            pkt = conn.recv(1024).decode('utf-8')
            if not pkt:
                break
            log.write(f'IN: {pkt}\n')
            print(f'Client: {pkt}')
            
            resp = input('Response: ')
            conn.sendall(resp.encode('utf-8'))
            log.write(f'OUT: {resp}\n')
            
            if input('Stop? (y/n): ') == 'y':
                break
    srv.close()

Client-Side Logging

Similarly, the client records outgoing messages and incoming replies to client_log.txt.

import socket

def run_logged_client(host='127.0.0.1', port=5050):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((host, port))
    
    with sock, open('client_log.txt', 'a', encoding='utf-8') as log:
        while True:
            text = input('Send: ')
            sock.sendall(text.encode('utf-8'))
            log.write(f'SENT: {text}\n')
            
            reply = sock.recv(1024).decode('utf-8')
            if not reply:
                break
            print(f'Reply: {reply}')
            log.write(f'RECV: {reply}\n')
            
            if input('Stop? (y/n): ') == 'y':
                break

Data Encryption Strategies

Secure transmission requires encrypting payloads before sending. While libraries like pycryptodome offer AES encryption, dependency issues may arise during installation. A lightweight alternative is XOR encryption for demonstration purposes.

XOR Cipher Helper

A reusbale function handles both encryption and decryption since XOR is symmetric.

def xor_transform(data_bytes, key_bytes):
    key_len = len(key_bytes)
    return bytes(b ^ key_bytes[i % key_len] for i, b in enumerate(data_bytes))

Encrypted Server

The server receives binary data, applies the XOR transformation using a shared secret, and saves the plaintext to a file.

import socket

def secure_server(host='127.0.0.1', port=6000):
    secret = b'SecureKey1234567' 
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((host, port))
    server.listen(1)
    print(f'Listening on {port}...')
    
    conn, _ = server.accept()
    try:
        cipher_text = conn.recv(4096)
        plain_text = xor_transform(cipher_text, secret)
        
        with open('decoded_data.bin', 'wb') as f:
            f.write(plain_text)
        print('Decryption complete. Saved to decoded_data.bin')
    finally:
        conn.close()
        server.close()

Encrypted Client

The client reads a local file, encrypts the content, and transmits the binary stream.

import socket

def secure_client(host='127.0.0.1', port=6000):
    secret = b'SecureKey1234567'
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        client.connect((host, port))
        
        with open('source_data.bin', 'rb') as f:
            raw_data = f.read()
        
        encrypted = xor_transform(raw_data, secret)
        client.sendall(encrypted)
        print('Encrypted payload sent.')
    except FileNotFoundError:
        print('Error: Source file not found.')
    finally:
        client.close()

Common Configuration Issues

During development, several environment-specific challenges may occur. Package managers like pip might fail to resolve dependencies for cryptographic libraries due to network restrictions or compiler missing errors. In such cases, verifying the Python version compatibility or switching to pure Python implementations (like the XOR example above) resolves the issue.

Additionally, configuration strings such as IP addresses or ports often contain hidden whitespace when copied from documentation. This leads to connection refused errors. Validating string inputs using .strip() ensures clean parameters are passed to socket binding functions.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

SBUS Signal Analysis and Communication Implementation Using STM32 with Fus Remote Controller

Overview In a recent project, I utilized the SBUS protocol with the Fus remote controller to control a vehicle's basic operations, including movement, lights, and mode switching. This article is aimed...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.