如何在Python中维护已连接客户端列表以向指定客户端请求文件
Python Socket多线程服务端维护客户端列表的方案
核心思路:用线程安全的存储结构保存所有活跃的客户端连接,接入时注册、断开时注销,需要定向发请求时从存储中取出对应客户端的连接对象即可。
1. 核心改造点
- 定义全局的客户端存储容器,推荐用字典,方便按唯一标识快速检索,键可以用客户端的(IP,端口)元组,也可以用客户端上报的业务ID,值存储socket连接对象和其他客户端信息
- 引入线程锁
threading.Lock,避免多线程同时读写存储容器时出现竞态问题 - 在
handle_client函数中补充连接断开的清理逻辑,避免无效连接残留
2. 完整修改后的代码
import socket import threading # 配置参数请根据自己的需求修改 IP = "0.0.0.0" PORT = 8888 ADDR = (IP, PORT) # 全局客户端存储字典:key为(客户端IP, 客户端端口),value为socket连接对象 active_clients = {} # 操作客户端字典的锁 client_lock = threading.Lock() def handle_client(conn, addr): client_ip, client_port = addr print(f"新客户端接入:{client_ip}:{client_port}") # 接入时将客户端加入存储 with client_lock: active_clients[(client_ip, client_port)] = conn try: # 这里是你原来的客户端处理逻辑,比如接收客户端消息等 while True: data = conn.recv(1024) if not data: break # 处理收到的数据的逻辑写在这里 print(f"收到{client_ip}:{client_port}的消息:{data.decode()}") except Exception as e: print(f"客户端{client_ip}:{client_port}连接异常:{str(e)}") finally: # 断开时从存储中移除客户端 with client_lock: if (client_ip, client_port) in active_clients: del active_clients[(client_ip, client_port)] conn.close() print(f"客户端{client_ip}:{client_port}已断开") def send_file_request_to_client(target_addr, request_msg): """ 向指定客户端发送文件请求的工具函数 target_addr: 目标客户端的(IP,端口)元组 request_msg: 给客户端的请求指令,比如"GET_FILE:xxx.txt" """ with client_lock: target_conn = active_clients.get(target_addr) if not target_conn: print(f"目标客户端{target_addr}不在线") return False try: target_conn.send(request_msg.encode()) return True except Exception as e: print(f"向{target_addr}发请求失败:{str(e)}") # 发送失败说明连接已失效,清理掉 with client_lock: if target_addr in active_clients: del active_clients[target_addr] target_conn.close() return False def main(): print("Starting the server") server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 使用IPV4和TCP连接 server.bind(ADDR) # 绑定地址 server.listen() # 开始监听 print(f"server is listening on {IP}: {PORT}") while True: conn, addr = server.accept() # 接受客户端连接 thread = threading.Thread(target = handle_client, args = (conn, addr)) # 为每个客户端分配线程 thread.start() # 可以在这里测试调用发请求的函数,比如给刚接入的客户端发请求 # send_file_request_to_client(addr, "GET_FILE:test.txt") if __name__ == "__main__": main()
3. 使用说明
要定向给指定客户端发文件请求时,直接调用send_file_request_to_client函数,传入目标客户端的(IP,端口)和请求指令即可。如果需要更友好的标识,可以在客户端接入后先让客户端上报用户名/设备ID作为字典的key,之后直接用业务ID查找客户端即可,不需要记忆IP端口。
注意事项
- 所有对
active_clients字典的读写操作都必须加锁,避免多线程并发修改导致的数据异常 - 每次操作连接对象时都要做异常捕获,出现错误及时清理无效连接,避免字典中残留已断开的连接
- 你可以根据自己的业务需求扩展
active_clients存储的内容,比如加入客户端的操作系统、权限等级等额外信息
内容的提问来源于stack exchange,提问作者Trung Nguyen
相关产品推荐
相关产品推荐

