多线程CLI聊天工具终端输出同步问题求助
解决CLI实时聊天工具的多线程终端输出混乱问题
问题根源
接收、发送线程同时对终端进行IO操作且无同步机制:
- 发送线程等待
input()时,终端显示用户名提示符 - 接收线程此时输出消息会打断当前输入行,造成提示符重复、消息错位
解决方案:用线程锁同步终端IO
所有涉及终端输出/输入的操作必须加锁,保证同一时间只有一个线程能操作终端。
步骤1:定义全局线程锁
在代码开头添加:
import threading terminal_lock = threading.Lock()
步骤2:修改输出函数,加锁执行
修改print_message、print_simple_message,确保输出操作互斥:
def print_message(message, sender_username): global username with terminal_lock: print(f"{sender_username}{message}") # 重新打印提示符,固定光标位置 print(colorama.Fore.GREEN + username + colorama.Fore.RESET, end='', flush=True) def print_simple_message(message, sender_username): with terminal_lock: print(f"{sender_username}: {message}") print(colorama.Fore.GREEN + username + colorama.Fore.RESET, end='', flush=True)
步骤3:修改发送线程的输入逻辑
将打印提示符和获取输入的过程加锁,避免被接收线程打断:
def send_messages(sock): global finished while not finished: with terminal_lock: print(colorama.Fore.GREEN + username + colorama.Fore.RESET, end='', flush=True) message = input() mes = message encrypt_message(sock, message) if mes == "exit()": with terminal_lock: print("You have left the room.") finished = True break
步骤4:修正接收线程的终端操作
接收线程中的换行、异常输出也需要加锁:
def receive_messages(sock): global finished while not finished: try: raw_message = sock.recv(1024).decode() with terminal_lock: # 换行将当前输入行顶出,避免消息覆盖提示符 print() raw_message = json.loads(raw_message) message_val = raw_message.get("Message") sender_username, _, message = message_val.partition(':') # 消息类型处理逻辑保持不变 if raw_message.get("Message_type") == MESSAGE_TYPE_JOIN_ROOM: message = " is connected" if raw_message.get("Message_type") == MESSAGE_TYPE_PUBLIC_KEY: if store_public_key(raw_message.get("Message")): continue message = " public key received" send_public_key(sock) if raw_message.get("Message_type") == MESSAGE_TYPE_LEAVE_ROOM: message = " is disconnected from room" if raw_message.get("Message_type") == MESSAGE_TYPE_SIMPLE_MESSAGE: message = decrypt_message(message) print_simple_message(message, sender_username) continue print_message(message, sender_username) except: with terminal_lock: print("An error occurred. Exiting.") finished = True break
关键细节
- 加
flush=True确保输出立即刷新到终端,避免缓存延迟导致的显示异常 - 每次输出消息后重新打印用户名提示符,保证光标回到正确输入位置
- 所有终端IO操作(
print/input)都通过锁互斥,彻底避免并发冲突
优化后输出示例
user:~/CLI_Chat_Tool$ python3 client.py private harry Connected to the server. @harry: @sam is connected @harry: @sam public key received @harry:hello @sam: hey @harry:hi @harry:
内容的提问来源于stack exchange,提问作者Pankaj
相关产品推荐
相关产品推荐

