杰瑞科技汇

Python socket accept阻塞,如何正确处理连接?

Of course! Let's break down the socket.accept() method in Python. It's a fundamental part of building network servers.

Python socket accept阻塞,如何正确处理连接?-图1
(图片来源网络,侵删)

The Core Concept: The Server-Model

socket.accept() is used exclusively on the server side of a network connection. It's the mechanism by which a server waits for a client to connect and then establishes a communication channel with that client.

Think of it like a receptionist at a busy office:

  1. socket.bind() & socket.listen(): The receptionist sets up the office address (bind) and puts a "We're Open" sign on the door, indicating they are ready to receive visitors (listen).
  2. socket.accept(): The receptionist waits by the door for someone to arrive. This is a blocking action—they can't do anything else until a client shows up.
  3. Client Arrives: A client (a visitor) comes to the door and knocks.
  4. Connection Established: The receptionist (accept) opens the door and says, "Come in! You can talk to me now." This action does two things:
    • It creates a new, private communication line (a new socket) between the receptionist and this specific visitor.
    • It gives the receptionist information about who just arrived (the visitor's address).

In Python, accept() returns both of these pieces of information.


The accept() Method Signature

new_socket, client_address = server_socket.accept()

When you call accept() on a listening server socket, it blocks (pauses execution) until a client connects. Once a client connects, it returns a tuple containing two elements:

Python socket accept阻塞,如何正确处理连接?-图2
(图片来源网络,侵删)
  1. new_socket: A new socket object. This is the crucial part. This new socket is used for all communication (sending and receiving data) with the specific client that just connected. The original server_socket is still free to call accept() again to listen for more incoming connections.
  2. client_address: A tuple containing the client's IP address and port number, in the format (ip_address, port). This is useful for logging or identifying who you are talking to.

A Simple Code Example: Echo Server

This is the classic "Hello, World!" of socket programming. A server that waits for a connection, receives a message from the client, and sends the exact same message back.

Server Code (server.py)

import socket
# 1. Create a TCP/IP socket (SOCK_STREAM for TCP)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. Bind the socket to a specific address and port
#    '' means listen on all available network interfaces
#    65432 is the port number (choose one > 1024 to avoid needing root)
server_address = ('', 65432)
print(f"Starting up on {server_address[0]} port {server_address[1]}")
server_socket.bind(server_address)
# 3. Listen for incoming connections
#    The '1' is the backlog, the number of unaccepted connections that the system
#    will allow before refusing new connections.
server_socket.listen(1)
# 4. The main loop: wait for a connection
print("Waiting for a connection...")
while True:
    # This is the blocking call. It waits here until a client connects.
    # When a client connects, it returns a new socket and the client's address.
    connection, client_address = server_socket.accept()
    # Now we have a connection to a specific client
    print(f"Connection from {client_address}")
    try:
        # 5. Receive data from the client (up to 1024 bytes)
        data = connection.recv(1024)
        print(f"Received: {data.decode('utf-8')}")
        # 6. Send the data back to the client (an echo)
        connection.sendall(data)
        print(f"Sent back: {data.decode('utf-8')}")
    finally:
        # 7. Clean up the connection
        print("Closing the current connection")
        connection.close()

Client Code (client.py)

import socket
# 1. Create a TCP socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. Connect to the server's address and port
#    Use '127.0.0.1' or 'localhost' if running on the same machine
server_address = ('127.0.0.1', 65432)
print(f"Connecting to {server_address[0]} port {server_address[1]}")
client_socket.connect(server_address)
try:
    # 3. Send data to the server
    message = b"Hello, Server! This is a test."
    print(f"Sending: {message.decode('utf-8')}")
    client_socket.sendall(message)
    # 4. Look for the response
    amount_received = 0
    amount_expected = len(message)
    while amount_received < amount_expected:
        data = client_socket.recv(4096)
        amount_received += len(data)
        print(f"Received: {data.decode('utf-8')}")
finally:
    # 5. Clean up
    print("Closing socket")
    client_socket.close()

How to Run the Example

  1. Save the server code as server.py and the client code as client.py.
  2. Open two terminal windows.
  3. In the first terminal, run the server:
    python server.py

    You will see:

    Python socket accept阻塞,如何正确处理连接?-图3
    (图片来源网络,侵删)
    Starting up on  port 65432
    Waiting for a connection...
  4. In the second terminal, run the client:
    python client.py

    You will see:

    Connecting to 127.0.0.1 port 65432
    Sending: Hello, Server! This is a test.
    Received: Hello, Server! This is a test.
    Closing socket
  5. Now, look back at the first terminal (the server). It will show:
    Connection from ('127.0.0.1', 54321)  # Port will vary
    Received: Hello, Server! This is a test.
    Sent back: Hello, Server! This is a test.
    Closing the current connection
    Waiting for a connection...

Key Points and Best Practices

  1. Blocking Nature: accept() is a blocking call. If your server needs to handle multiple clients simultaneously without waiting, you cannot just call it in a simple loop. For this, you would use:

    • Threading: Create a new thread for each client returned by accept().
    • select module: Use select.select() to monitor multiple sockets for activity (ready for reading/writing) in a single thread.
    • Asynchronous I/O (asyncio): The modern, high-performance way to handle many concurrent connections.
  2. Separate Sockets: Remember that server_socket is for accepting connections. The new_socket returned by accept() is for communicating with a specific client. Don't try to send data with the server socket.

  3. Error Handling: Network operations can fail (e.g., the client disconnects unexpectedly). It's good practice to wrap your communication logic in a try...finally or try...except block to ensure you always close the connection, as shown in the example. This prevents resource leaks.

分享:
扫描分享到社交APP
上一篇
下一篇