TCP Client Implementation

Building a TCP client with detailed explanations of each step

Introduction

In this notebook, we’ll implement a TCP client that: 1. Creates a socket 2. Connects to a server 3. Sends and receives data 4. Closes the connection gracefully

Let’s import the necessary modules:

Simple TCP Client

We’ll start with a basic TCP client implementation:


source

TCPClient

 TCPClient (buffer_size:int=1024)

A simple TCP client for connecting to TCP servers.

Enhanced TCP Client with Asynchronous Receive

Now let’s create a more advanced client with asynchronous message reception:


source

AsyncTCPClient

 AsyncTCPClient (buffer_size:int=1024)

A TCP client with asynchronous message reception in a background thread.

Event-Driven TCP Client

Finally, let’s create an event-driven TCP client with detailed connection state events:


source

EventDrivenTCPClient

 EventDrivenTCPClient (buffer_size:int=1024)

A TCP client that emits events for connection state changes.

c = EventDrivenTCPClient()
c.connect(LOCALHOST, 8000)
c.send(b"Hello, server!")
c.receive()
c.close()
Connecting to 127.0.0.1:8000...
Error connecting to 127.0.0.1:8000: [Errno 111] Connection refused
Connection closed
Not connected to a server
Not connected to a server

Example Usage

Here’s a simple example of how to use our basic TCP client:

def simple_client_demo():
    # Create a TCP client
    client = TCPClient()
    
    # Connect to a server
    if client.connect(LOCALHOST, 8000):
        try:
            # Send a message
            client.send(b"Hello, server!")
            
            # Receive the response
            response = client.receive()
            if response:
                print(f"Received from server: {response.decode('utf-8')}")
            
            # Send another message
            client.send(b"How are you?")
            
            # Receive the response
            response = client.receive()
            if response:
                print(f"Received from server: {response.decode('utf-8')}")
                
        finally:
            # Close the connection
            client.close()

# Uncomment to run the demo (make sure a server is running)
# simple_client_demo()

Let’s see a more advanced example with the event-driven client:

def event_driven_client_demo():
    # Create an event-driven TCP client
    client = EventDrivenTCPClient()
    
    # Set up event handlers
    client.on_connect = lambda host, port: print(f"EVENT: Connected to {host}:{port}")
    client.on_disconnect = lambda: print("EVENT: Disconnected from server")
    client.on_data = lambda data: print(f"EVENT: Received data: {data.decode('utf-8')}")
    client.on_error = lambda error: print(f"EVENT: Error occurred: {error}")
    
    # Connect to a server
    if client.connect(LOCALHOST, 8000):
        try:
            # Send some messages
            client.send(b"Hello from event-driven client!")
            time.sleep(1)
            
            client.send(b"This client uses events for processing responses.")
            time.sleep(1)
            
            # Wait for a while to receive responses
            print("Waiting for responses...")
            time.sleep(3)
            
        finally:
            # Close the connection
            client.close()

# Uncomment to run the demo (make sure a server is running)
# event_driven_client_demo()