Wie man Nachrichten mit Python Sockets sendet und empfängt

PythonBeginner
Jetzt üben

Einführung

Python Sockets (Sockets) bieten ein leistungsstarkes Werkzeug für die Netzwerkkommunikation und ermöglichen das Senden und Empfangen von Nachrichten über verschiedene Systeme hinweg. In diesem Tutorial führen wir Sie durch den Prozess der Verwendung von Python Sockets, um Verbindungen herzustellen, Daten zu übertragen und Antworten zu empfangen. Am Ende dieses Labs haben Sie sowohl eine Client- als auch eine Server-Anwendung erstellt, die über ein Netzwerk miteinander kommunizieren können.

Dieses praktische Wissen bildet die Grundlage für die Entwicklung komplexerer Netzwerk-Anwendungen, von Chat-Programmen bis hin zu verteilten Systemen.

Grundlagen von Sockets verstehen und Ihr erstes Socket erstellen

Beginnen wir damit, zu verstehen, was Sockets sind und wie sie in Python funktionieren. Anschließend erstellen wir unser erstes Socket, um zu sehen, wie es initialisiert wird.

Was sind Python Sockets?

Sockets sind Endpunkte zum Senden und Empfangen von Daten über ein Netzwerk. Sie bieten eine Programmierschnittstelle für die Netzwerkkommunikation und ermöglichen Anwendungen den Informationsaustausch unabhängig von ihrem Standort.

In der Netzwerkprogrammierung verwenden wir typischerweise ein Client-Server-Modell:

  • Der Server wartet auf eingehende Verbindungen und verarbeitet Anfragen.
  • Der Client initiiert die Kommunikation, indem er sich mit dem Server verbindet.

Das in Python integrierte socket-Modul erleichtert die Arbeit mit Sockets, ohne alle komplexen Details der Netzwerkprotokolle verstehen zu müssen.

Socket-Typen

Die beiden gebräuchlichsten Socket-Typen sind:

  • TCP (Transmission Control Protocol): Bietet zuverlässige, geordnete Datenübermittlung.
  • UDP (User Datagram Protocol): Bietet schnellere, aber unzuverlässige Datenübertragung.

In diesem Lab konzentrieren wir uns auf TCP-Sockets, die der am häufigsten verwendete Typ für Anwendungen sind, die eine zuverlässige Kommunikation erfordern.

Erstellen Ihres ersten Sockets

Lassen Sie uns ein einfaches Python-Skript erstellen, um ein Socket zu initialisieren. Öffnen Sie die WebIDE und führen Sie die folgenden Schritte aus:

  1. Erstellen wir zunächst ein Verzeichnis für unser Socket-Programmierprojekt:
mkdir -p ~/project/socket_lab
cd ~/project/socket_lab
  1. Erstellen Sie nun eine neue Python-Datei namens socket_basics.py:

Klicken Sie in der WebIDE auf die Schaltfläche "New File" oder verwenden Sie das Menü "File" und wählen Sie "New File", und benennen Sie sie dann socket_basics.py innerhalb des Verzeichnisses socket_lab.

  1. Fügen Sie den folgenden Code hinzu, um zu demonstrieren, wie man ein Socket erstellt:
import socket

## Creating a socket
print("Creating a new socket...")
my_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print(f"Socket created: {my_socket}")

## Explaining the parameters:
print("\nSocket parameters explained:")
print("AF_INET: Using IPv4 addressing")
print("SOCK_STREAM: Using TCP protocol for reliable data transmission")

## Getting available socket methods
print("\nSome methods available on socket objects:")
methods = [method for method in dir(my_socket) if not method.startswith('_')]
print(', '.join(methods[:10]) + '...')  ## Showing first 10 methods

## Closing the socket
my_socket.close()
print("\nSocket closed")
  1. Speichern Sie die Datei.

  2. Führen Sie das Skript aus, um die Ausgabe zu sehen:

python3 ~/project/socket_lab/socket_basics.py

Sie sollten eine Ausgabe ähnlich dieser sehen:

Creating a new socket...
Socket created: <socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('0.0.0.0', 0)>

Socket parameters explained:
AF_INET: Using IPv4 addressing
SOCK_STREAM: Using TCP protocol for reliable data transmission

Some methods available on socket objects:
accept, bind, close, connect, connect_ex, detach, fileno, getpeername, getsockname, getsockopt...

Socket closed

Diese Ausgabe zeigt, dass wir erfolgreich ein Socket-Objekt erstellt und einige seiner Eigenschaften untersucht haben. In den nächsten Abschnitten verwenden wir Sockets, um eine Server- und Client-Anwendung zu erstellen, die miteinander kommunizieren können.

Wichtige Socket-Funktionen

Bevor wir fortfahren, wollen wir einige wichtige Socket-Funktionen verstehen, die wir verwenden werden:

  • socket() - Erstellt ein neues Socket-Objekt
  • bind() - Ordnet das Socket einer bestimmten Netzwerkschnittstelle und einem Port zu
  • listen() - Ermöglicht dem Server, Verbindungen zu akzeptieren
  • accept() - Akzeptiert eine Verbindung von einem Client
  • connect() - Verbindet sich mit einer Remote-Adresse
  • send() - Sendet Daten an ein verbundenes Socket
  • recv() - Empfängt Daten von einem verbundenen Socket
  • close() - Schließt das Socket

Im nächsten Schritt erstellen wir einen Server mit diesen Funktionen.

Erstellen eines einfachen Socket-Servers

Nachdem wir die Grundlagen von Sockets verstanden haben, erstellen wir einen einfachen Server, der auf Verbindungen wartet und Nachrichten von Clients empfängt.

Wie ein Socket-Server funktioniert

Ein Socket-Server folgt diesen allgemeinen Schritten:

  1. Erstellen Sie ein Socket
  2. Binden Sie es an eine Adresse und einen Port
  3. Warten Sie auf eingehende Verbindungen
  4. Akzeptieren Sie Client-Verbindungen
  5. Empfangen und verarbeiten Sie Daten
  6. Senden Sie bei Bedarf eine Antwort
  7. Schließen Sie die Verbindung

Lassen Sie uns dieses Muster in Python implementieren.

Erstellen des Servers

  1. Erstellen Sie eine neue Python-Datei namens server.py im Verzeichnis socket_lab:

Klicken Sie in der WebIDE auf die Schaltfläche "New File" oder verwenden Sie das Menü "File" und wählen Sie "New File", und benennen Sie sie dann server.py innerhalb des Verzeichnisses socket_lab.

  1. Fügen Sie den folgenden Code hinzu, um einen einfachen Server zu erstellen:
import socket

def start_server():
    ## Server configuration
    host = '127.0.0.1'  ## localhost
    port = 12345        ## arbitrary non-privileged port

    ## Create socket
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    ## Set socket option to reuse address (helps avoid "Address already in use" errors)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    ## Bind socket to address and port
    server_socket.bind((host, port))

    ## Listen for connections (queue up to 5 connection requests)
    server_socket.listen(5)

    print(f"Server started on {host}:{port}")
    print("Waiting for client connection...")

    try:
        ## Accept connection
        client_socket, client_address = server_socket.accept()
        print(f"Connection established with {client_address}")

        ## Receive data from client
        data = client_socket.recv(1024)  ## receive up to 1024 bytes
        print(f"Message received: {data.decode()}")

        ## Send response to client
        response = "Message received by server"
        client_socket.send(response.encode())

        ## Close client connection
        client_socket.close()

    except KeyboardInterrupt:
        print("\nServer shutting down...")
    finally:
        ## Close server socket
        server_socket.close()
        print("Server socket closed")

if __name__ == "__main__":
    start_server()
  1. Speichern Sie die Datei.

Verstehen des Server-Codes

Lassen Sie uns die Schlüsselkomponenten unseres Servers aufschlüsseln:

  • Socket-Erstellung: Wir erstellen ein TCP-Socket mit socket.socket() mit AF_INET (IPv4) und SOCK_STREAM (TCP-Protokoll).

  • Socket-Optionen: Wir setzen eine Option, um die Adresse wiederzuverwenden, was hilft, Fehler vom Typ "Address already in use" zu vermeiden, wenn der Server nach dem Herunterfahren schnell neu gestartet wird.

  • Binden: Wir binden das Socket an die Adresse 127.0.0.1 (localhost) und den Port 12345. Dies teilt dem Betriebssystem mit, dass wir Verbindungen an diesem bestimmten Netzwerkstandort empfangen möchten.

  • Warten auf Verbindungen: Der Aufruf listen(5) weist das Socket an, bis zu 5 Verbindungsanforderungen in die Warteschlange zu stellen, bevor neue Verbindungen abgelehnt werden.

  • Akzeptieren von Verbindungen: Die Methode accept() blockiert (wartet), bis sich ein Client verbindet, und gibt dann ein neues Socket-Objekt für die Kommunikation mit diesem Client zusammen mit der Adresse des Clients zurück.

  • Empfangen von Daten: Wir verwenden recv(1024), um bis zu 1024 Bytes an Daten vom Client zu empfangen. Die Daten kommen als Bytes, daher verwenden wir decode(), um sie in eine Zeichenkette umzuwandeln.

  • Senden von Daten: Wir senden eine Antwort zurück an den Client mit der Methode send(). Wir encode() die Zeichenkette, um sie vor dem Senden in Bytes umzuwandeln.

  • Schließen: Schließlich schließen wir sowohl das Client-Socket als auch das Server-Socket, um Ressourcen freizugeben.

Testen des Servers

Lassen Sie uns unseren Server ausführen, um ihn in Aktion zu sehen. Er wird noch nicht viel tun, da wir noch keinen Client erstellt haben, aber wir können überprüfen, ob er korrekt startet:

python3 ~/project/socket_lab/server.py

Sie sollten eine Ausgabe wie diese sehen:

Server started on 127.0.0.1:12345
Waiting for client connection...

Der Server wartet jetzt auf eine Client-Verbindung. Da wir noch keinen Client haben, drücken Sie Strg+C, um den Server zu stoppen:

^C
Server shutting down...
Server socket closed

Im nächsten Schritt erstellen wir einen Client, um sich mit unserem Server zu verbinden.

Erstellen eines Clients zur Verbindung mit dem Server

Nachdem wir unseren Server haben, müssen wir einen Client erstellen, der sich damit verbinden und Nachrichten senden kann. Lassen Sie uns eine einfache Client-Anwendung erstellen.

Wie ein Socket-Client funktioniert

Ein Socket-Client folgt diesen allgemeinen Schritten:

  1. Erstellen Sie ein Socket
  2. Verbinden Sie sich mit der Adresse und dem Port eines Servers
  3. Senden Sie Daten
  4. Empfangen Sie eine Antwort
  5. Schließen Sie die Verbindung

Erstellen des Clients

  1. Erstellen Sie eine neue Python-Datei namens client.py im Verzeichnis socket_lab:

Klicken Sie in der WebIDE auf die Schaltfläche "New File" oder verwenden Sie das Menü "File" und wählen Sie "New File", und benennen Sie sie dann client.py innerhalb des Verzeichnisses socket_lab.

  1. Fügen Sie den folgenden Code hinzu, um einen einfachen Client zu erstellen:
import socket

def start_client():
    ## Server information to connect to
    host = '127.0.0.1'  ## localhost - same as server
    port = 12345        ## same port as server

    try:
        ## Create socket
        client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        ## Connect to server
        print(f"Connecting to server at {host}:{port}...")
        client_socket.connect((host, port))
        print("Connected to server")

        ## Send a message
        message = "Hello from the client!"
        print(f"Sending message: {message}")
        client_socket.send(message.encode())

        ## Receive response
        response = client_socket.recv(1024)
        print(f"Response from server: {response.decode()}")

    except ConnectionRefusedError:
        print("Connection failed. Make sure the server is running.")
    except Exception as e:
        print(f"An error occurred: {e}")
    finally:
        ## Close socket
        client_socket.close()
        print("Connection closed")

if __name__ == "__main__":
    start_client()
  1. Speichern Sie die Datei.

Verstehen des Client-Codes

Lassen Sie uns die wichtigsten Teile unseres Client-Codes untersuchen:

  • Socket-Erstellung: Ähnlich wie beim Server erstellen wir ein TCP-Socket mit socket.socket().

  • Verbindung: Anstatt zu binden und zu warten, verwendet der Client connect(), um eine Verbindung zum Server unter dem angegebenen Host und Port herzustellen.

  • Senden von Daten: Wir senden eine Nachricht mit der Methode send() und stellen sicher, dass die Zeichenkette in Bytes codiert wird.

  • Empfangen von Daten: Wir verwenden recv(1024), um die Antwort des Servers zu empfangen und sie wieder in eine Zeichenkette zu decodieren.

  • Fehlerbehandlung: Wir fügen eine Fehlerbehandlung ein, um häufige Probleme wie die Nichtverfügbarkeit des Servers (ConnectionRefusedError) zu erfassen.

  • Schließen: Wir schließen das Socket, wenn wir fertig sind, um Ressourcen freizugeben.

Testen von Client und Server zusammen

Lassen Sie uns nun unseren Client und Server zusammen testen. Wir müssen sie in separaten Terminalfenstern ausführen.

  1. Starten Sie zuerst den Server:
python3 ~/project/socket_lab/server.py

Sie sollten Folgendes sehen:

Server started on 127.0.0.1:12345
Waiting for client connection...
  1. Öffnen Sie ein neues Terminal in der WebIDE (indem Sie auf die Schaltfläche "+" im Terminal-Panel klicken) und führen Sie den Client aus:
python3 ~/project/socket_lab/client.py

Sie sollten im Client-Terminal eine Ausgabe wie diese sehen:

Connecting to server at 127.0.0.1:12345...
Connected to server
Sending message: Hello from the client!
Response from server: Message received by server
Connection closed

Und im Server-Terminal sollten Sie Folgendes sehen:

Connection established with ('127.0.0.1', 55234)  ## The port number may differ
Message received: Hello from the client!

Nachdem der Client die Verbindung getrennt hat, stoppt der Server, da unsere aktuelle Implementierung nur eine einzelne Verbindung verarbeitet. Drücken Sie Strg+C im Server-Terminal, um es herunterzufahren, falls es noch läuft.

Dies demonstriert die erfolgreiche Kommunikation zwischen einem Client und einem Server unter Verwendung von Python-Sockets. Der Client kann eine Nachricht an den Server senden, und der Server kann sie empfangen und eine Antwort zurücksenden.

Erstellen eines kontinuierlichen Servers und eines interaktiven Clients

Unsere aktuelle Server-Client-Implementierung verarbeitet nur einen einzelnen Nachrichtenaustausch, bevor sie geschlossen wird. Die meisten realen Anwendungen müssen Verbindungen aufrechterhalten und mehrere Nachrichten verarbeiten. Lassen Sie uns unseren Code verbessern, um eine interaktivere Erfahrung zu schaffen.

Verbessern des Servers

Zuerst ändern wir unseren Server so, dass er kontinuierlich Verbindungen akzeptiert und mehrere Nachrichten von jedem Client verarbeitet.

  1. Öffnen Sie die Datei server.py in der WebIDE und ersetzen Sie den Code durch:
import socket

def start_server():
    ## Server configuration
    host = '127.0.0.1'
    port = 12345

    ## Create socket
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    try:
        ## Bind and listen
        server_socket.bind((host, port))
        server_socket.listen(5)

        print(f"Server running on {host}:{port}")
        print("Press Ctrl+C to stop the server")

        while True:  ## Continuous server loop
            print("\nWaiting for a connection...")
            client_socket, client_address = server_socket.accept()
            print(f"Connected to client: {client_address}")

            ## Handle client communication
            handle_client(client_socket)

    except KeyboardInterrupt:
        print("\nServer is shutting down...")
    finally:
        server_socket.close()
        print("Server closed")

def handle_client(client_socket):
    try:
        while True:  ## Keep receiving messages until client disconnects
            ## Receive data
            data = client_socket.recv(1024)

            ## If no data, client has disconnected
            if not data:
                break

            received_message = data.decode()
            print(f"Received: {received_message}")

            ## Process the message (in this case, just echo it back with a prefix)
            response = f"Server received: {received_message}"
            client_socket.send(response.encode())

    except Exception as e:
        print(f"Error handling client: {e}")
    finally:
        ## Close client socket
        client_socket.close()
        print("Client connection closed")

if __name__ == "__main__":
    start_server()
  1. Speichern Sie die Datei.

Verbessern des Clients

Nun erstellen wir einen interaktiven Client, der es Benutzern ermöglicht, mehrere Nachrichten zu senden.

  1. Öffnen Sie die Datei client.py in der WebIDE und ersetzen Sie den Code durch:
import socket

def start_client():
    ## Server information
    host = '127.0.0.1'
    port = 12345

    try:
        ## Create socket and connect
        client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        print(f"Connecting to server at {host}:{port}...")
        client_socket.connect((host, port))
        print("Connected to server!")

        ## Interactive message sending
        while True:
            ## Get message from user
            message = input("\nEnter message to send (or 'quit' to exit): ")

            ## Check if user wants to quit
            if message.lower() == 'quit':
                print("Closing connection...")
                break

            ## Send message
            client_socket.send(message.encode())

            ## Receive response
            response = client_socket.recv(1024)
            print(f"Response from server: {response.decode()}")

    except ConnectionRefusedError:
        print("Connection failed. Make sure the server is running.")
    except Exception as e:
        print(f"An error occurred: {e}")
    finally:
        ## Close connection
        try:
            client_socket.close()
        except:
            pass
        print("Disconnected from server")

if __name__ == "__main__":
    start_client()
  1. Speichern Sie die Datei.

Verstehen des verbesserten Codes

Server-Erweiterungen:

  • Wir haben eine äußere while True-Schleife hinzugefügt, um kontinuierlich neue Client-Verbindungen zu akzeptieren.
  • Wir haben eine separate Funktion handle_client erstellt, um die Kommunikation mit jedem Client zu verwalten.
  • Die Client-Handling-Funktion hat ihre eigene Schleife, um mehrere Nachrichten vom selben Client zu empfangen.
  • Wir prüfen auf leere Daten (if not data:), was anzeigt, dass der Client die Verbindung getrennt hat.

Client-Erweiterungen:

  • Wir haben eine while True-Schleife hinzugefügt, um das Senden mehrerer Nachrichten zu ermöglichen.
  • Wir fordern den Benutzer zur Eingabe auf und senden diese an den Server.
  • Der Benutzer kann 'quit' eingeben, um die Schleife zu verlassen und die Verbindung zu schließen.
  • Nach dem Senden jeder Nachricht warten wir auf die Antwort des Servers und zeigen sie an.

Testen der erweiterten Anwendungen

Lassen Sie uns unseren erweiterten Server und Client testen:

  1. Starten Sie den erweiterten Server in einem Terminal:
python3 ~/project/socket_lab/server.py

Sie sollten Folgendes sehen:

Server running on 127.0.0.1:12345
Press Ctrl+C to stop the server

Waiting for a connection...
  1. Führen Sie im neuen Terminal den erweiterten Client aus:
python3 ~/project/socket_lab/client.py

Sie sollten Folgendes sehen:

Connecting to server at 127.0.0.1:12345...
Connected to server!

Enter message to send (or 'quit' to exit):
  1. Geben Sie eine Nachricht ein und drücken Sie die Eingabetaste:
Enter message to send (or 'quit' to exit): Hello, server!
Response from server: Server received: Hello, server!

Enter message to send (or 'quit' to exit):
  1. Versuchen Sie, ein paar weitere Nachrichten zu senden. Im Server-Terminal sollten Sie sehen, dass jede Nachricht empfangen wird:
Connected to client: ('127.0.0.1', 59042)
Received: Hello, server!
Received: This is another message
  1. Wenn Sie fertig sind, geben Sie 'quit' im Client ein:
Enter message to send (or 'quit' to exit): quit
Closing connection...
Disconnected from server
  1. Im Server-Terminal sollten Sie Folgendes sehen:
Client connection closed

Waiting for a connection...
  1. Der Server läuft weiter und ist bereit, neue Verbindungen zu akzeptieren. Sie können einen anderen Client starten oder Strg+C drücken, um den Server zu stoppen.

Mit diesen Erweiterungen haben wir ein realistischeres und interaktiveres Client-Server-Kommunikationssystem mit Python-Sockets erstellt.

Mehrere Clients und Fehlerbehandlung

In realen Anwendungen muss ein Server typischerweise mehrere Clients gleichzeitig verarbeiten und verschiedene Fehlerbedingungen ordnungsgemäß verwalten. Lassen Sie uns unsere Implementierung unter Berücksichtigung dieser Aspekte verbessern.

Verstehen der gleichzeitigen Client-Verarbeitung

Es gibt verschiedene Möglichkeiten, mehrere Clients gleichzeitig zu verarbeiten:

  1. Threading (Thread-basiert): Erstellen Sie einen neuen Thread für jede Client-Verbindung
  2. Prozessbasiert: Erstellen Sie einen neuen Prozess für jeden Client
  3. Asynchrones I/O: Verwenden Sie nicht-blockierendes I/O mit einer Ereignisschleife

Für dieses Lab implementieren wir einen Threading-basierten Ansatz, der relativ einfach zu verstehen und zu implementieren ist.

Verbessern des Servers für mehrere Clients

Lassen Sie uns unseren Server so modifizieren, dass er mehrere Clients mithilfe von Threads verarbeitet:

  1. Öffnen Sie die Datei server.py in der WebIDE und ersetzen Sie den Code durch:
import socket
import threading

def handle_client(client_socket, client_address):
    """Handle communication with a single client"""
    try:
        print(f"[NEW CONNECTION] {client_address} connected.")

        while True:
            ## Receive client data
            try:
                data = client_socket.recv(1024)
                if not data:
                    break  ## Client disconnected

                message = data.decode()
                print(f"[{client_address}] {message}")

                ## Send response
                response = f"Message '{message}' received successfully"
                client_socket.send(response.encode())

            except ConnectionResetError:
                print(f"[{client_address}] Connection reset by client")
                break

    except Exception as e:
        print(f"[ERROR] {e}")

    finally:
        ## Clean up when client disconnects
        client_socket.close()
        print(f"[DISCONNECTED] {client_address} disconnected")

def start_server():
    """Start the server and listen for connections"""
    ## Server configuration
    host = '127.0.0.1'
    port = 12345

    ## Create socket
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    ## Set socket option to reuse address
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    try:
        ## Bind to host and port
        server_socket.bind((host, port))

        ## Listen for connections
        server_socket.listen(5)
        print(f"[STARTING] Server is listening on {host}:{port}")

        while True:
            ## Accept client connection
            client_socket, client_address = server_socket.accept()

            ## Create a new thread to handle the client
            client_thread = threading.Thread(
                target=handle_client,
                args=(client_socket, client_address)
            )
            client_thread.daemon = True  ## Thread will close when main program exits
            client_thread.start()

            ## Display active connections
            print(f"[ACTIVE CONNECTIONS] {threading.active_count() - 1}")

    except KeyboardInterrupt:
        print("\n[SHUTTING DOWN] Server is shutting down...")
    except Exception as e:
        print(f"[ERROR] {e}")
    finally:
        server_socket.close()
        print("[CLOSED] Server socket closed")

if __name__ == "__main__":
    start_server()
  1. Speichern Sie die Datei.

Verbessern des Clients mit Fehlerbehandlung

Lassen Sie uns auch unseren Client mit besserer Fehlerbehandlung verbessern:

  1. Öffnen Sie die Datei client.py in der WebIDE und ersetzen Sie den Code durch:
import socket
import sys
import time

def start_client():
    """Start a client that connects to the server"""
    ## Server information
    host = '127.0.0.1'
    port = 12345

    ## Create socket
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    ## Set a timeout for connection attempts (5 seconds)
    client_socket.settimeout(5)

    try:
        ## Connect to server
        print(f"[CONNECTING] Connecting to server at {host}:{port}...")
        client_socket.connect((host, port))

        ## Reset timeout to none for regular communication
        client_socket.settimeout(None)

        print("[CONNECTED] Connected to server")

        ## Communication loop
        while True:
            ## Get user input
            message = input("\nEnter message (or 'quit' to exit): ")

            if message.lower() == 'quit':
                print("[CLOSING] Closing connection by request...")
                break

            try:
                ## Send message
                client_socket.send(message.encode())

                ## Wait for response
                response = client_socket.recv(1024)
                print(f"[RESPONSE] {response.decode()}")

            except ConnectionResetError:
                print("[ERROR] Connection was reset by the server")
                break
            except ConnectionAbortedError:
                print("[ERROR] Connection was aborted")
                break
            except Exception as e:
                print(f"[ERROR] {e}")
                break

    except socket.timeout:
        print("[TIMEOUT] Connection attempt timed out. Is the server running?")
    except ConnectionRefusedError:
        print("[REFUSED] Connection refused. Make sure the server is running.")
    except KeyboardInterrupt:
        print("\n[INTERRUPT] Client shutting down...")
    except Exception as e:
        print(f"[ERROR] {e}")

    finally:
        ## Close socket
        try:
            client_socket.close()
            print("[DISCONNECTED] Disconnected from server")
        except:
            pass

if __name__ == "__main__":
    start_client()
  1. Speichern Sie die Datei.

Verstehen des verbesserten Codes

Server-Erweiterungen:

  • Wir haben das threading-Modul hinzugefügt, um mehrere Clients gleichzeitig zu verarbeiten.
  • Jede Client-Verbindung wird jetzt in einem separaten Thread verarbeitet.
  • Wir haben die Fehlerbehandlung mit spezifischeren Ausnahmen verbessert.
  • Wir zeigen die Anzahl der aktiven Client-Verbindungen an.
  • Threads werden als "Daemon" gesetzt, was bedeutet, dass sie automatisch geschlossen werden, wenn das Hauptprogramm beendet wird.

Client-Erweiterungen:

  • Wir haben ein Verbindungstimeout hinzugefügt, um zu verhindern, dass der Client hängen bleibt, wenn der Server nicht verfügbar ist.
  • Wir haben die Fehlerbehandlung mit spezifischen Ausnahmen für verschiedene Netzwerkfehler verbessert.
  • Wir haben beschreibendere Statusmeldungen mit klarer Formatierung hinzugefügt.

Testen des Multi-Client-Servers

Lassen Sie uns unsere verbesserten Anwendungen testen:

  1. Starten Sie den Server:
python3 ~/project/socket_lab/server.py

Sie sollten Folgendes sehen:

[STARTING] Server is listening on 127.0.0.1:12345
  1. Starten Sie in einem neuen Terminal einen Client:
python3 ~/project/socket_lab/client.py
  1. Starten Sie einen weiteren Client in einem dritten Terminal:
python3 ~/project/socket_lab/client.py
  1. Im Server-Terminal sollten Sie beide Verbindungen sehen:
[NEW CONNECTION] ('127.0.0.1', 59124) connected.
[ACTIVE CONNECTIONS] 1
[NEW CONNECTION] ('127.0.0.1', 59126) connected.
[ACTIVE CONNECTIONS] 2
  1. Senden Sie Nachrichten von beiden Clients und beobachten Sie, wie der Server sie empfängt:
[('127.0.0.1', 59124)] Hello from client 1
[('127.0.0.1', 59126)] Hello from client 2
  1. Wenn Sie fertig sind, geben Sie in jedem Client 'quit' ein, um die Verbindung zu trennen, oder drücken Sie Strg+C im Server-Terminal, um den Server herunterzufahren.

Umgang mit nicht laufendem Server

Lassen Sie uns auch testen, was passiert, wenn der Server nicht läuft:

  1. Stellen Sie sicher, dass der Server gestoppt ist (drücken Sie Strg+C, falls er läuft).

  2. Versuchen Sie, einen Client auszuführen:

python3 ~/project/socket_lab/client.py

Sie sollten Folgendes sehen:

[CONNECTING] Connecting to server at 127.0.0.1:12345...
[REFUSED] Connection refused. Make sure the server is running.
[DISCONNECTED] Disconnected from server

Der Client behandelt den Fehler jetzt ordnungsgemäß und informiert den Benutzer, dass der Server möglicherweise nicht läuft.

Mit diesen Erweiterungen haben wir ein robustes Client-Server-System erstellt, das mehrere Clients und verschiedene Fehlerbedingungen verarbeiten kann. Dies ist eine solide Grundlage für die Entwicklung komplexerer Netzwerk-Anwendungen.

Zusammenfassung

Herzlichen Glückwunsch zum Abschluss dieses Labs zum Python-Socket-Programming. Sie haben erfolgreich gelernt, wie man:

  1. Socket-Objekte (Socket-Objekte) für die Netzwerkkommunikation erstellt
  2. Einen TCP-Server implementiert, der auf Verbindungen wartet
  3. Eine Client-Anwendung erstellt, die sich mit einem Server verbindet
  4. Nachrichten zwischen Client und Server sendet und empfängt
  5. Ihren Server erweitert, um mehrere Clients gleichzeitig zu verarbeiten
  6. Eine robuste Fehlerbehandlung sowohl im Client als auch im Server implementiert

Diese Fähigkeiten bilden die Grundlage der Netzwerkprogrammierung und können verwendet werden, um eine Vielzahl von Netzwerk-Anwendungen zu erstellen, von einfachen Chat-Programmen bis hin zu komplexen verteilten Systemen.

Um Ihre Lernreise fortzusetzen, sollten Sie Folgendes in Betracht ziehen:

  • Implementierung sicherer Socket-Verbindungen mit SSL/TLS
  • Erstellung eines komplexeren Protokolls für den Austausch strukturierter Daten
  • Erstellung einer GUI (Graphical User Interface) für Ihre Client-Anwendung
  • Verwendung von asynchronem I/O für höhere Leistung bei vielen gleichzeitigen Verbindungen

Pythons Socket-Programmierfähigkeiten machen es zu einer ausgezeichneten Wahl für die Entwicklung von Netzwerkanwendungen und bieten ein Gleichgewicht aus Einfachheit und Leistung, das nur wenige andere Sprachen erreichen können.