Wie man Nachrichten mit Python-Sockets sendet und empfängt

PythonPythonBeginner
Jetzt üben

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Introduction

Python sockets provide a powerful tool for network communication, enabling you to send and receive messages across different systems. In this tutorial, we will guide you through the process of using Python sockets to establish connections, transmit data, and receive responses. By the end of this lab, you will have built both a client and server application that can communicate with each other over a network.

This practical knowledge forms the foundation for developing more complex networked applications, from chat programs to distributed systems.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/ErrorandExceptionHandlingGroup(["Error and Exception Handling"]) python(("Python")) -.-> python/FileHandlingGroup(["File Handling"]) python(("Python")) -.-> python/AdvancedTopicsGroup(["Advanced Topics"]) python(("Python")) -.-> python/NetworkingGroup(["Networking"]) python(("Python")) -.-> python/ControlFlowGroup(["Control Flow"]) python(("Python")) -.-> python/ModulesandPackagesGroup(["Modules and Packages"]) python/ControlFlowGroup -.-> python/while_loops("While Loops") python/ModulesandPackagesGroup -.-> python/using_packages("Using Packages") python/ErrorandExceptionHandlingGroup -.-> python/catching_exceptions("Catching Exceptions") python/FileHandlingGroup -.-> python/file_operations("File Operations") python/AdvancedTopicsGroup -.-> python/threading_multiprocessing("Multithreading and Multiprocessing") python/NetworkingGroup -.-> python/socket_programming("Socket Programming") python/NetworkingGroup -.-> python/http_requests("HTTP Requests") python/NetworkingGroup -.-> python/networking_protocols("Networking Protocols") subgraph Lab Skills python/while_loops -.-> lab-398244{{"Wie man Nachrichten mit Python-Sockets sendet und empfängt"}} python/using_packages -.-> lab-398244{{"Wie man Nachrichten mit Python-Sockets sendet und empfängt"}} python/catching_exceptions -.-> lab-398244{{"Wie man Nachrichten mit Python-Sockets sendet und empfängt"}} python/file_operations -.-> lab-398244{{"Wie man Nachrichten mit Python-Sockets sendet und empfängt"}} python/threading_multiprocessing -.-> lab-398244{{"Wie man Nachrichten mit Python-Sockets sendet und empfängt"}} python/socket_programming -.-> lab-398244{{"Wie man Nachrichten mit Python-Sockets sendet und empfängt"}} python/http_requests -.-> lab-398244{{"Wie man Nachrichten mit Python-Sockets sendet und empfängt"}} python/networking_protocols -.-> lab-398244{{"Wie man Nachrichten mit Python-Sockets sendet und empfängt"}} end

Understanding Socket Basics and Creating Your First Socket

Let us start by understanding what sockets are and how they work in Python. We will then create our first socket to see how it is initialized.

What are Python Sockets?

Sockets are endpoints for sending and receiving data across a network. They provide a programming interface to network communication, allowing applications to exchange information regardless of their location.

In network programming, we typically use a client-server model:

  • The server waits for incoming connections and processes requests
  • The client initiates communication by connecting to the server

Python's built-in socket module makes it easy to work with sockets without needing to understand all the complex details of network protocols.

Socket Types

The two most common socket types are:

  • TCP (Transmission Control Protocol): Provides reliable, ordered delivery of data
  • UDP (User Datagram Protocol): Provides faster but unreliable data transmission

For this lab, we will focus on TCP sockets, which are the most commonly used type for applications requiring reliable communication.

Creating Your First Socket

Let's create a simple Python script to initialize a socket. Open the WebIDE and follow these steps:

  1. First, let's create a directory for our socket programming project:
mkdir -p ~/project/socket_lab
cd ~/project/socket_lab
  1. Now, create a new Python file called socket_basics.py:

In the WebIDE, click on the "New File" button or use the "File" menu and select "New File", then name it socket_basics.py within the socket_lab directory.

  1. Add the following code to demonstrate how to create a socket:
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. Save the file.

  2. Run the script to see the output:

python3 ~/project/socket_lab/socket_basics.py

You should see output similar to this:

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

This output shows that we've successfully created a socket object and explored some of its properties. In the next sections, we'll use sockets to build a server and client application that can communicate with each other.

Key Socket Functions

Before moving on, let's understand some key socket functions that we will be using:

  • socket() - Creates a new socket object
  • bind() - Associates the socket with a specific network interface and port
  • listen() - Enables the server to accept connections
  • accept() - Accepts a connection from a client
  • connect() - Connects to a remote address
  • send() - Sends data to a connected socket
  • recv() - Receives data from a connected socket
  • close() - Closes the socket

In the next step, we will create a server using these functions.

Creating a Simple Socket Server

Now that we understand the basics of sockets, let's create a simple server that listens for connections and receives messages from clients.

How a Socket Server Works

A socket server follows these general steps:

  1. Create a socket
  2. Bind it to an address and port
  3. Listen for incoming connections
  4. Accept client connections
  5. Receive and process data
  6. Send a response if needed
  7. Close the connection

Let's implement this pattern in Python.

Creating the Server

  1. Create a new Python file called server.py in the socket_lab directory:

In the WebIDE, click on the "New File" button or use the "File" menu and select "New File", then name it server.py within the socket_lab directory.

  1. Add the following code to create a basic server:
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. Save the file.

Understanding the Server Code

Let's break down the key components of our server:

  • Socket Creation: We create a TCP socket using socket.socket() with AF_INET (IPv4) and SOCK_STREAM (TCP protocol).

  • Socket Options: We set an option to reuse the address, which helps prevent "Address already in use" errors when restarting the server quickly after shutdown.

  • Binding: We bind the socket to the address 127.0.0.1 (localhost) and port 12345. This tells the operating system that we want to receive connections at this specific network location.

  • Listening: The listen(5) call tells the socket to queue up to 5 connection requests before refusing new connections.

  • Accepting Connections: The accept() method blocks (waits) until a client connects, then returns a new socket object for communicating with that client, along with the client's address.

  • Receiving Data: We use recv(1024) to receive up to 1024 bytes of data from the client. The data comes as bytes, so we use decode() to convert it to a string.

  • Sending Data: We send a response back to the client using the send() method. We encode() the string to convert it to bytes before sending.

  • Closing: Finally, we close both the client socket and the server socket to release resources.

Testing the Server

Let's run our server to see it in action. It won't do much yet since we haven't created a client, but we can verify it starts correctly:

python3 ~/project/socket_lab/server.py

You should see output like this:

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

The server is now waiting for a client to connect. Since we don't have a client yet, press Ctrl+C to stop the server:

^C
Server shutting down...
Server socket closed

In the next step, we'll create a client to connect to our server.

Building a Client to Connect to the Server

Now that we have our server, we need to create a client that can connect to it and send messages. Let's build a simple client application.

How a Socket Client Works

A socket client follows these general steps:

  1. Create a socket
  2. Connect to a server's address and port
  3. Send data
  4. Receive a response
  5. Close the connection

Creating the Client

  1. Create a new Python file called client.py in the socket_lab directory:

In the WebIDE, click on the "New File" button or use the "File" menu and select "New File", then name it client.py within the socket_lab directory.

  1. Add the following code to create a basic client:
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. Save the file.

Understanding the Client Code

Let's examine the key parts of our client code:

  • Socket Creation: Similar to the server, we create a TCP socket using socket.socket().

  • Connection: Instead of binding and listening, the client uses connect() to establish a connection to the server at the specified host and port.

  • Sending Data: We send a message using the send() method, making sure to encode the string to bytes.

  • Receiving Data: We use recv(1024) to receive the server's response, and decode it back to a string.

  • Error Handling: We include error handling to catch common issues like the server not being available (ConnectionRefusedError).

  • Closing: We close the socket when we're done to free up resources.

Testing Client and Server Together

Now let's test our client and server together. We'll need to run them in separate terminal windows.

  1. First, start the server:
python3 ~/project/socket_lab/server.py

You should see:

Server started on 127.0.0.1:12345
Waiting for client connection...
  1. Open a new terminal in WebIDE (by clicking the "+" button in the terminal panel), and run the client:
python3 ~/project/socket_lab/client.py

You should see output like this in the client terminal:

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

And in the server terminal, you should see:

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

After the client disconnects, the server will stop because our current implementation only handles a single connection. Press Ctrl+C in the server terminal to shut it down if it's still running.

This demonstrates successful communication between a client and server using Python sockets. The client is able to send a message to the server, and the server can receive it and send a response back.

Building a Continuous Server and Interactive Client

Our current server-client implementation only handles a single message exchange before closing. Most real-world applications need to maintain connections and handle multiple messages. Let's enhance our code to create a more interactive experience.

Enhancing the Server

First, let's modify our server to continuously accept connections and handle multiple messages from each client.

  1. Open the server.py file in the WebIDE and replace the code with:
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. Save the file.

Enhancing the Client

Now, let's create an interactive client that allows users to send multiple messages.

  1. Open the client.py file in the WebIDE and replace the code with:
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. Save the file.

Understanding the Enhanced Code

Server Enhancements:

  • We added an outer while True loop to continuously accept new client connections
  • We created a separate handle_client function to manage communication with each client
  • The client handling function has its own loop to receive multiple messages from the same client
  • We check for empty data (if not data:), which indicates the client has disconnected

Client Enhancements:

  • We added a while True loop to allow sending multiple messages
  • We prompt the user for input and send it to the server
  • The user can type 'quit' to exit the loop and close the connection
  • After sending each message, we wait for and display the server's response

Testing the Enhanced Applications

Let's test our enhanced server and client:

  1. Start the enhanced server in a terminal:
python3 ~/project/socket_lab/server.py

You should see:

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

Waiting for a connection...
  1. In a new terminal, run the enhanced client:
python3 ~/project/socket_lab/client.py

You should see:

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

Enter message to send (or 'quit' to exit):
  1. Type a message and press Enter:
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. Try sending a few more messages. In the server terminal, you should see each message being received:
Connected to client: ('127.0.0.1', 59042)
Received: Hello, server!
Received: This is another message
  1. When you're done, type 'quit' in the client:
Enter message to send (or 'quit' to exit): quit
Closing connection...
Disconnected from server
  1. In the server terminal, you should see:
Client connection closed

Waiting for a connection...
  1. The server continues running and is ready to accept new connections. You can start another client or press Ctrl+C to stop the server.

With these enhancements, we've created a more realistic and interactive client-server communication system using Python sockets.

Multiple Clients and Error Handling

In real-world applications, a server typically needs to handle multiple clients simultaneously and gracefully manage various error conditions. Let's improve our implementation with these considerations in mind.

Understanding Concurrent Client Handling

There are several ways to handle multiple clients concurrently:

  1. Threading: Create a new thread for each client connection
  2. Process-based: Spawn a new process for each client
  3. Asynchronous I/O: Use non-blocking I/O with an event loop

For this lab, we'll implement a threading-based approach, which is relatively simple to understand and implement.

Enhancing the Server for Multiple Clients

Let's modify our server to handle multiple clients using threads:

  1. Open the server.py file in the WebIDE and replace the code with:
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. Save the file.

Improving the Client with Error Handling

Let's also enhance our client with better error handling:

  1. Open the client.py file in the WebIDE and replace the code with:
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. Save the file.

Understanding the Enhanced Code

Server Enhancements:

  • We've added the threading module to handle multiple clients concurrently
  • Each client connection is now handled in a separate thread
  • We've improved error handling with more specific exception catches
  • We display the number of active client connections
  • Threads are set as "daemon", which means they'll automatically close when the main program exits

Client Enhancements:

  • We've added a connection timeout to prevent hanging if the server isn't available
  • We've improved error handling with specific exception catches for different network errors
  • We've added more descriptive status messages with clear formatting

Testing the Multi-Client Server

Let's test our improved applications:

  1. Start the server:
python3 ~/project/socket_lab/server.py

You should see:

[STARTING] Server is listening on 127.0.0.1:12345
  1. In a new terminal, start a client:
python3 ~/project/socket_lab/client.py
  1. Start another client in a third terminal:
python3 ~/project/socket_lab/client.py
  1. In the server terminal, you should see both connections:
[NEW CONNECTION] ('127.0.0.1', 59124) connected.
[ACTIVE CONNECTIONS] 1
[NEW CONNECTION] ('127.0.0.1', 59126) connected.
[ACTIVE CONNECTIONS] 2
  1. Send messages from both clients and observe the server receiving them:
[('127.0.0.1', 59124)] Hello from client 1
[('127.0.0.1', 59126)] Hello from client 2
  1. When you're done, type 'quit' in each client to disconnect, or press Ctrl+C in the server terminal to shut down the server.

Handling Server Not Running

Let's also test what happens when the server isn't running:

  1. Make sure the server is stopped (press Ctrl+C if it's running)

  2. Try to run a client:

python3 ~/project/socket_lab/client.py

You should see:

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

The client now handles the error gracefully, informing the user that the server might not be running.

With these enhancements, we've created a robust client-server system that can handle multiple clients and various error conditions. This is a solid foundation for developing more complex networked applications.

Summary

Congratulations on completing this lab on Python socket programming. You've successfully learned how to:

  1. Create socket objects for network communication
  2. Implement a TCP server that listens for connections
  3. Build a client application that connects to a server
  4. Send and receive messages between client and server
  5. Enhance your server to handle multiple clients concurrently
  6. Implement robust error handling in both client and server

These skills form the foundation of network programming and can be applied to build a wide range of networked applications, from simple chat programs to complex distributed systems.

To continue your learning journey, consider exploring:

  • Implementing secure socket connections with SSL/TLS
  • Building a more complex protocol for exchanging structured data
  • Creating a GUI for your client application
  • Using asynchronous I/O for higher performance with many concurrent connections

Python's socket programming capabilities make it an excellent choice for network application development, offering a balance of simplicity and power that few other languages can match.