You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何取消Python中input()引发的阻塞线程?TCP客户端场景答疑

Hey there! Let's work through your TCP client threading problem with those blocking input() calls — I’ve run into similar scenarios before, so let’s break this down step by step.

核心问题分析

The root issue here is that input() is a blocking call: when your client thread is waiting for user input, it can’t simultaneously listen for incoming messages from the server. That means if the server sends a notification to all clients after someone enters 'X', the blocked threads won’t see that message until the user enters something — which defeats the purpose of the real-time notification.

To fix this, we need to split the client’s responsibilities into two separate threads:

  • One thread dedicated to handling user input and sending commands to the server
  • Another thread dedicated to listening for incoming messages from the server (and acting on them immediately)
解决方案:拆分输入与消息监听线程

By separating these two tasks, neither will block the other. The input thread can wait for user commands without missing server notifications, and the listener thread can react to server messages the moment they arrive.

完整代码示例

客户端代码

This client spins up a daemon thread to listen for server messages, while the main thread handles user input:

import socket
import threading

def listen_for_server_messages(client_socket):
    """Thread dedicated to receiving and handling server notifications"""
    while True:
        try:
            # Receive message from server (1024 byte buffer)
            message = client_socket.recv(1024).decode('utf-8')
            if not message:
                print("\nServer disconnected. Exiting...")
                break
            # Print server notifications (use \n to avoid overlapping with input prompt)
            print(f"\n[Server Notification]: {message}")
            # If you need to trigger specific logic here, add it below
            # Example: if "continue" in message: do_something()
        except Exception as e:
            print(f"\nError receiving message: {str(e)}")
            break

def run_client():
    HOST = '127.0.0.1'
    PORT = 12345

    # Create TCP socket and connect to server
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        client_socket.connect((HOST, PORT))
        print(f"Connected to server at {HOST}:{PORT}")

        # Start the message listener thread (daemon=True means it exits when main thread does)
        listener_thread = threading.Thread(target=listen_for_server_messages, args=(client_socket,), daemon=True)
        listener_thread.start()

        # Main loop for user input
        while True:
            user_command = input("Enter command (type 'X' to trigger server notification): ")
            # Send command to server
            client_socket.send(user_command.encode('utf-8'))
            if user_command.lower() == 'x':
                print("Sent 'X' command — waiting for server to notify others...")

    except ConnectionRefusedError:
        print("Could not connect to server. Is it running?")
    except Exception as e:
        print(f"Client error: {str(e)}")
    finally:
        client_socket.close()
        print("Client disconnected.")

if __name__ == "__main__":
    run_client()

服务器代码

The server needs to track all connected clients, and when it receives an 'X' command, send a notification to every client except the one that sent it:

import socket
import threading

# List to keep track of all connected client sockets
connected_clients = []

def handle_client(client_socket, client_address):
    print(f"New client connected: {client_address}")
    connected_clients.append(client_socket)

    try:
        while True:
            # Receive command from client
            command = client_socket.recv(1024).decode('utf-8')
            if not command:
                break
            print(f"Received from {client_address}: {command}")

            # If command is 'X', notify all other clients
            if command == 'X':
                notification = f"Client {client_address} has triggered the 'X' command — the program will continue!"
                for client in connected_clients:
                    if client != client_socket:
                        try:
                            client.send(notification.encode('utf-8'))
                        except Exception as e:
                            print(f"Failed to send notification to client: {str(e)}")
    except Exception as e:
        print(f"Error handling client {client_address}: {str(e)}")
    finally:
        print(f"Client {client_address} disconnected")
        connected_clients.remove(client_socket)
        client_socket.close()

def run_server():
    HOST = '127.0.0.1'
    PORT = 12345

    # Create TCP socket and start listening
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind((HOST, PORT))
    server_socket.listen(5)
    print(f"Server running on {HOST}:{PORT} — waiting for clients...")

    # Accept new clients indefinitely
    while True:
        client_socket, client_address = server_socket.accept()
        # Spin up a new thread to handle each client
        client_thread = threading.Thread(target=handle_client, args=(client_socket, client_address))
        client_thread.start()

if __name__ == "__main__":
    run_server()
额外注意事项
  • Daemon Threads: The listener thread uses daemon=True so it automatically exits when the main client thread closes — no need to manually manage its lifecycle.
  • Error Handling: The code includes basic error handling for disconnections and network issues, but you can expand this based on your app’s needs (e.g., reconnection logic).
  • Thread Safety: The server’s connected_clients list is modified by multiple threads — for production code, you should add a lock (like threading.Lock()) to prevent race conditions when adding/removing clients.
  • Input Prompt Cleanup: Using \n in server notifications ensures they don’t overlap with the user’s input prompt, making the UI cleaner.

内容的提问来源于stack exchange,提问作者lkonrad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:36:58