主机A
import socket
import threading
import mouse
import time
from pynput import keyboard
class RemoteMouseClient:
def __init__(self, server_ip, server_port):
self.server_ip = server_ip
self.server_port = server_port
self.server_socket = None
self.is_running = True
self.lock = threading.Lock() # 增加锁机制
self.unacknowledged_messages = [] # 存储未确认消息
def connect_to_server(self):
while self.is_running:
try:
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.connect((self.server_ip, self.server_port))
print(f"成功连接到服务器 {self.server_ip}:{self.server_port}")
threading.Thread(target=self.receive_acknowledgements).start()
break
except socket.error as e:
print(f"无法连接到服务器,正在重试... 错误: {e}")
time.sleep(5) # 5秒后重试连接
def send_event(self, message):
with self.lock:
self.unacknowledged_messages.append(message)
self.send_message(message)
def send_message(self, message):
if self.server_socket:
try:
self.server_socket.send(message.encode())
except socket.error as e:
print(f"发送数据时出错: {e}")
self.server_socket.close()
self.connect_to_server() # 重新连接服务器
def receive_acknowledgements(self):
while self.is_running:
try:
data = self.server_socket.recv(1024).decode()
if data:
with self.lock:
if data in self.unacknowledged_messages:
self.unacknowledged_messages.remove(data)
except socket.error as e:
print(f"接收确认消息时出错: {e}")
break
def track_mouse(self):
def on_move(event):
if isinstance(event, mouse.MoveEvent):
x, y = event.x, event.y
self.send_event(f'move,{x},{y},0,0')
def on_click(event):
if isinstance(event, mouse.ButtonEvent):
x, y = mouse.get_position() # 获取当前鼠标位置
if event.event_type == mouse.DOWN:
self.send_event(f'{event.button}_down,{x},{y},0,0')
elif event.event_type == mouse.UP:
self.send_event(f'{event.button}_up,{x},{y},0,0')
def on_scroll(event):
if isinstance(event, mouse.WheelEvent):
x, y = event.x, event.y
self.send_event(f'scroll,{x},{y},{event.delta_x},{event.delta_y}')
mouse.hook(on_move)
mouse.hook(on_click)
mouse.hook(on_scroll)
while self.is_running:
time.sleep(1) # Keep the thread running
def track_keyboard(self):
def on_press(key):
try:
self.send_event(f'key_down,{key.char}')
except AttributeError:
self.send_event(f'key_down,{key.name}')
def on_release(key):
try:
self.send_event(f'key_up,{key.char}')
except AttributeError:
self.send_event(f'key_up,{key.name}')
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
def start(self):
self.connect_to_server()
mouse_thread = threading.Thread(target=self.track_mouse)
mouse_thread.start()
keyboard_thread = threading.Thread(target=self.track_keyboard)
keyboard_thread.start()
def stop(self):
self.is_running = False
if self.server_socket:
self.server_socket.close()
if __name__ == "__main__":
client = RemoteMouseClient('172.18.254.19', 12345)
try:
client.start()
except KeyboardInterrupt:
client.stop()
print("客户端已停止。")
主机B
import socket
import threading
import pyautogui
import pystray
from PIL import Image, ImageDraw
from pynput.keyboard import Controller as KeyboardController, Key
import sys
# 客户端监听的端口
client_listen_port = 12345
# 创建一个事件来控制线程的运行
stop_event = threading.Event()
keyboard_controller = KeyboardController()
def receive_commands():
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind(('0.0.0.0', client_listen_port))
listen_socket.listen(5)
print(f"Listening for commands on port {client_listen_port}")
while not stop_event.is_set():
conn, addr = listen_socket.accept()
threading.Thread(target=handle_command, args=(conn,)).start()
def handle_command(conn):
while not stop_event.is_set():
try:
data = conn.recv(1024).decode()
if not data:
break
parts = data.split(',')
action = parts[0]
if action.startswith('key'):
key = parts[1]
handle_keyboard(action, key)
else:
x, y = int(parts[1]), int(parts[2])
dx, dy = int(parts[3]), int(parts[4])
handle_mouse(action, x, y, dx, dy)
# 发送确认消息
conn.send(data.encode())
except Exception as e:
print(f"处理命令时出错: {e}")
break
conn.close()
def handle_mouse(action, x, y, dx, dy):
if action == 'move':
pyautogui.moveTo(x, y)
elif action.startswith('left') or action.startswith('right') or action.startswith('middle'):
button = action.split('_')[0]
if 'down' in action:
pyautogui.mouseDown(x, y, button=button)
elif 'up' in action:
pyautogui.mouseUp(x, y, button=button)
elif action == 'scroll':
pyautogui.scroll(dy, x, y)
def handle_keyboard(action, key):
try:
if len(key) == 1: # 单个字符键
if action == 'key_down':
keyboard_controller.press(key)
elif action == 'key_up':
keyboard_controller.release(key)
else: # 特殊键
key = getattr(Key, key, None)
if key:
if action == 'key_down':
keyboard_controller.press(key)
elif action == 'key_up':
keyboard_controller.release(key)
except AttributeError as e:
print(f"按键处理时出错: {e}")
def create_image(width, height, color1, color2):
image = Image.new('RGB', (width, height), color1)
dc = ImageDraw.Draw(image)
dc.rectangle((width // 2, 0, width, height // 2), fill=color2)
dc.rectangle((0, height // 2, width // 2, height), fill=color2)
return image
def on_quit(icon, item):
stop_event.set() # 设置停止事件
icon.stop()
sys.exit()
# 创建系统托盘图标
icon_image = create_image(64, 64, 'blue', 'black')
menu = pystray.Menu(pystray.MenuItem('Quit', on_quit))
icon = pystray.Icon("RemoteMouseClient", icon_image, "客户端", menu)
# 启动命令接收线程
receive_thread = threading.Thread(target=receive_commands, daemon=True)
receive_thread.start()
# 启动系统托盘图标
icon.run()
# 保持主线程运行
while not stop_event.is_set():
pass
# pyinstaller --onefile --noconsole 客户端v4.0.py
服务器4.1
import socket
import threading
import mouse
import time
from pynput import keyboard
import tkinter as tk
from tkinter import ttk
class RemoteMouseClient:
def __init__(self, server_ip, server_port):
self.server_ip = server_ip
self.server_port = server_port
self.server_socket = None
self.is_running = False # 初始状态为未运行
self.lock = threading.Lock() # 增加锁机制
self.unacknowledged_messages = [] # 存储未确认消息
def connect_to_server(self):
"""
尝试连接到服务器,如果连接失败则每隔5秒重试。
"""
while self.is_running:
try:
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.connect((self.server_ip, self.server_port))
print(f"成功连接到服务器 {self.server_ip}:{self.server_port}")
self.update_status("已经建立了连接")
self.update_connected_host_info()
threading.Thread(target=self.receive_acknowledgements).start()
break
except socket.error as e:
print(f"无法连接到服务器,正在重试... 错误: {e}")
self.update_status("连接已断开")
time.sleep(5) # 5秒后重试连接
def send_event(self, message):
"""
将事件消息发送到服务器,并添加到未确认消息列表中。
"""
with self.lock:
self.unacknowledged_messages.append(message)
self.send_message(message)
def send_message(self, message):
"""
发送消息到服务器,并在发送失败时重新连接服务器。
"""
if self.server_socket and self.is_running:
try:
self.server_socket.send(message.encode())
except socket.error as e:
print(f"发送数据时出错: {e}")
self.server_socket.close()
self.connect_to_server() # 重新连接服务器
def receive_acknowledgements(self):
"""
从服务器接收确认消息,并从未确认消息列表中移除确认的消息。
"""
while self.is_running:
try:
data = self.server_socket.recv(1024).decode()
if data:
with self.lock:
if data in self.unacknowledged_messages:
self.unacknowledged_messages.remove(data)
except socket.error as e:
print(f"接收确认消息时出错: {e}")
break
def track_mouse(self):
"""
追踪鼠标事件并发送相应事件消息到服务器。
"""
def on_move(event):
if isinstance(event, mouse.MoveEvent):
x, y = event.x, event.y
self.send_event(f'move,{x},{y},0,0')
def on_click(event):
if isinstance(event, mouse.ButtonEvent):
x, y = mouse.get_position() # 获取当前鼠标位置
if event.event_type == mouse.DOWN:
self.send_event(f'{event.button}_down,{x},{y},0,0')
elif event.event_type == mouse.UP:
self.send_event(f'{event.button}_up,{x},{y},0,0')
def on_scroll(event):
if isinstance(event, mouse.WheelEvent):
x, y = event.x, event.y
self.send_event(f'scroll,{x},{y},{event.delta_x},{event.delta_y}')
mouse.hook(on_move)
mouse.hook(on_click)
mouse.hook(on_scroll)
while self.is_running:
time.sleep(1) # 保持线程运行
def track_keyboard(self):
"""
追踪键盘事件并发送相应事件消息到服务器。
"""
def on_press(key):
if self.is_running:
try:
self.send_event(f'key_down,{key.char}')
except AttributeError:
self.send_event(f'key_down,{key.name}')
def on_release(key):
if self.is_running:
try:
self.send_event(f'key_up,{key.char}')
except AttributeError:
self.send_event(f'key_up,{key.name}')
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
def start(self):
"""
启动客户端,连接服务器并开始追踪鼠标和键盘事件。
"""
self.is_running = True
self.connect_to_server()
mouse_thread = threading.Thread(target=self.track_mouse)
mouse_thread.start()
keyboard_thread = threading.Thread(target=self.track_keyboard)
keyboard_thread.start()
def stop(self):
"""
停止客户端,断开与服务器的连接。
"""
self.is_running = False
if self.server_socket:
self.server_socket.close()
self.update_status("连接已断开")
self.update_connected_host_info(reset=True)
def update_status(self, status):
"""
更新GUI中的连接状态。
"""
if gui:
gui.update_status(status)
def update_connected_host_info(self, reset=False):
"""
更新GUI中已连接的主机信息。
"""
if gui:
if reset:
gui.update_connected_host_info("连接已断开")
else:
gui.update_connected_host_info(f"{self.server_ip}:{self.server_port}")
class RemoteMouseClientGUI:
def __init__(self, client):
self.client = client
self.root = tk.Tk()
self.root.title("Remote Mouse Client")
self.root.configure(bg='#ffffff') # 主界面颜色
# 设置样式
style = ttk.Style(self.root)
style.configure('TLabel', font=('Helvetica', 10), background='#f6f8fa', foreground='#3b71a3')
style.configure('TButton', font=('Helvetica', 10), background='#f6f8fa', foreground='#3b71a3')
style.map('TButton', background=[('active', '#e0e4e8')])
# 创建主框架
main_frame = tk.Frame(self.root, bg='#f6f8fa', bd=1, relief='solid', highlightthickness=1,
highlightbackground='#dce2e8')
main_frame.pack(fill='both', expand=True, padx=10, pady=10)
# 创建状态标签
self.status_label = ttk.Label(main_frame, text="连接状态: 未连接", style='TLabel')
self.status_label.pack(pady=10)
# 创建启动按钮
self.start_button = ttk.Button(main_frame, text="启动连接", command=self.start_connection)
self.start_button.pack(pady=5)
# 创建终止按钮
self.stop_button = ttk.Button(main_frame, text="终止连接", command=self.stop_connection)
self.stop_button.pack(pady=5)
# 创建已连接主机标签
self.connected_host_label = ttk.Label(main_frame, text="已连接主机", anchor='w', style='TLabel')
self.connected_host_label.pack(fill='x', padx=10)
# 创建已连接主机信息文本框
self.connected_host_info = tk.Text(main_frame, height=1, width=30, state='disabled', font=('Helvetica', 10),
bg='#f6f8fa', fg='#3b71a3', bd=0, highlightthickness=1,
highlightbackground='#dce2e8')
self.connected_host_info.pack(pady=10)
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
self.center_window()
def center_window(self):
"""
将窗口居中显示。
"""
self.root.update_idletasks()
width = self.root.winfo_width()
height = self.root.winfo_height()
x = (self.root.winfo_screenwidth() // 2) - (width // 2)
y = (self.root.winfo_screenheight() // 2) - (height // 2)
self.root.geometry(f'{width}x{height}+{x}+{y}')
def start_connection(self):
"""
启动连接线程。
"""
threading.Thread(target=self.client.start).start()
self.update_status("正在尝试连接...")
def stop_connection(self):
"""
停止连接。
"""
self.client.stop()
self.update_status("连接已断开")
def update_status(self, status):
"""
更新连接状态标签的文本。
"""
self.status_label.config(text=f"连接状态: {status}")
def update_connected_host_info(self, info):
"""
更新已连接主机信息文本框的内容。
"""
self.connected_host_info.config(state='normal')
self.connected_host_info.delete(1.0, tk.END)
self.connected_host_info.insert(tk.END, info)
self.connected_host_info.config(state='disabled')
def on_closing(self):
"""
处理窗口关闭事件。
"""
self.client.stop()
self.root.destroy()
print("客户端已停止。")
self.root.quit()
def run(self):
"""
运行GUI主循环。
"""
self.root.mainloop()
if __name__ == "__main__":
client = RemoteMouseClient('172.18.254.19', 12345)
gui = RemoteMouseClientGUI(client)
try:
gui.run()
except KeyboardInterrupt:
client.stop()
print("客户端已停止。")
服务器4.2
import socket
import threading
import mouse
import time
from pynput import keyboard
import tkinter as tk
from tkinter import ttk
class RemoteMouseClient:
def __init__(self, server_ip, server_port):
self.server_ip = server_ip
self.server_port = server_port
self.server_socket = None
self.is_running = False # 初始状态为未运行
self.lock = threading.Lock() # 增加锁机制
self.unacknowledged_messages = [] # 存储未确认消息
self.failed_messages = [] # 存储未成功发送的消息
def connect_to_server(self):
while self.is_running:
try:
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # 设置SO_KEEPALIVE
self.server_socket.connect((self.server_ip, self.server_port))
print(f"成功连接到服务器 {self.server_ip}:{self.server_port}")
self.update_status("已经建立了连接")
self.update_connected_host_info()
threading.Thread(target=self.receive_acknowledgements).start()
self.resend_failed_messages() # 重新发送未成功发送的消息
break
except socket.error as e:
print(f"无法连接到服务器,正在重试... 错误: {e}")
self.update_status("连接已断开")
time.sleep(5) # 5秒后重试连接
def send_event(self, message):
with self.lock:
self.unacknowledged_messages.append(message)
self.send_message(message)
def send_message(self, message):
if self.server_socket and self.is_running:
try:
self.server_socket.send(message.encode())
except socket.error as e:
print(f"发送数据时出错: {e}")
self.failed_messages.append(message) # 记录未成功发送的消息
self.server_socket.close()
self.connect_to_server() # 重新连接服务器
def receive_acknowledgements(self):
while self.is_running:
try:
data = self.server_socket.recv(1024).decode()
if data:
with self.lock:
if data in self.unacknowledged_messages:
self.unacknowledged_messages.remove(data)
except socket.error as e:
print(f"接收确认消息时出错: {e}")
self.server_socket.close()
self.connect_to_server() # 重新连接服务器
break
def resend_failed_messages(self):
"""
重新发送所有未成功发送的消息。
"""
with self.lock:
for message in self.failed_messages:
self.send_message(message)
self.failed_messages.clear()
def track_mouse(self):
def on_move(event):
if isinstance(event, mouse.MoveEvent):
x, y = event.x, event.y
self.send_event(f'move,{x},{y},0,0')
def on_click(event):
if isinstance(event, mouse.ButtonEvent):
x, y = mouse.get_position() # 获取当前鼠标位置
if event.event_type == mouse.DOWN:
self.send_event(f'{event.button}_down,{x},{y},0,0')
elif event.event_type == mouse.UP:
self.send_event(f'{event.button}_up,{x},{y},0,0')
def on_scroll(event):
if isinstance(event, mouse.WheelEvent):
x, y = event.x, event.y
self.send_event(f'scroll,{x},{y},{event.delta_x},{event.delta_y}')
mouse.hook(on_move)
mouse.hook(on_click)
mouse.hook(on_scroll)
while self.is_running:
time.sleep(1) # 保持线程运行
def track_keyboard(self):
def on_press(key):
if self.is_running:
try:
self.send_event(f'key_down,{key.char}')
except AttributeError:
self.send_event(f'key_down,{key.name}')
def on_release(key):
if self.is_running:
try:
self.send_event(f'key_up,{key.char}')
except AttributeError:
self.send_event(f'key_up,{key.name}')
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
def start(self):
self.is_running = True
self.connect_to_server()
mouse_thread = threading.Thread(target=self.track_mouse)
mouse_thread.start()
keyboard_thread = threading.Thread(target=self.track_keyboard)
keyboard_thread.start()
def stop(self):
self.is_running = False
if self.server_socket:
self.server_socket.close()
self.update_status("连接已断开")
self.update_connected_host_info(reset=True)
def update_status(self, status):
if gui:
gui.update_status(status)
def update_connected_host_info(self, reset=False):
if gui:
if reset:
gui.update_connected_host_info("连接已断开")
else:
gui.update_connected_host_info(f"{self.server_ip}:{self.server_port}")
class RemoteMouseClientGUI:
def __init__(self, client):
self.client = client
self.root = tk.Tk()
self.root.title("Remote Mouse Client")
self.root.configure(bg='#ffffff') # 主界面颜色
# 设置样式
style = ttk.Style(self.root)
style.configure('TLabel', font=('Helvetica', 10), background='#f6f8fa', foreground='#3b71a3')
style.configure('TButton', font=('Helvetica', 10), background='#f6f8fa', foreground='#3b71a3')
style.map('TButton', background=[('active', '#e0e4e8')])
# 创建主框架
main_frame = tk.Frame(self.root, bg='#f6f8fa', bd=1, relief='solid', highlightthickness=1,
highlightbackground='#dce2e8')
main_frame.pack(fill='both', expand=True, padx=10, pady=10)
# 创建状态标签
self.status_label = ttk.Label(main_frame, text="连接状态: 未连接", style='TLabel')
self.status_label.pack(pady=10)
# 创建启动按钮
self.start_button = ttk.Button(main_frame, text="启动连接", command=self.start_connection)
self.start_button.pack(pady=5)
# 创建终止按钮
self.stop_button = ttk.Button(main_frame, text="终止连接", command=self.stop_connection)
self.stop_button.pack(pady=5)
# 创建已连接主机标签
self.connected_host_label = ttk.Label(main_frame, text="已连接主机", anchor='w', style='TLabel')
self.connected_host_label.pack(fill='x', padx=10)
# 创建已连接主机信息文本框
self.connected_host_info = tk.Text(main_frame, height=1, width=30, state='disabled', font=('Helvetica', 10),
bg='#f6f8fa', fg='#3b71a3', bd=0, highlightthickness=1,
highlightbackground='#dce2e8')
self.connected_host_info.pack(pady=10)
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
self.center_window()
def center_window(self):
"""
将窗口居中显示。
"""
self.root.update_idletasks()
width = self.root.winfo_width()
height = self.root.winfo_height()
x = (self.root.winfo_screenwidth() // 2) - (width // 2)
y = (self.root.winfo_screenheight() // 2) - (height // 2)
self.root.geometry(f'{width}x{height}+{x}+{y}')
def start_connection(self):
"""
启动连接线程。
"""
threading.Thread(target=self.client.start).start()
self.update_status("正在尝试连接...")
def stop_connection(self):
"""
停止连接。
"""
self.client.stop()
self.update_status("连接已断开")
def update_status(self, status):
"""
更新连接状态标签的文本。
"""
self.status_label.config(text=f"连接状态: {status}")
def update_connected_host_info(self, info):
"""
更新已连接主机信息文本框的内容。
"""
self.connected_host_info.config(state='normal')
self.connected_host_info.delete(1.0, tk.END)
self.connected_host_info.insert(tk.END, info)
self.connected_host_info.config(state='disabled')
def on_closing(self):
"""
处理窗口关闭事件。
"""
self.client.stop()
self.root.destroy()
print("客户端已停止。")
self.root.quit()
def run(self):
"""
运行GUI主循环。
"""
self.root.mainloop()
if __name__ == "__main__":
client = RemoteMouseClient('172.18.254.19', 12345)
gui = RemoteMouseClientGUI(client)
try:
gui.run()
except KeyboardInterrupt:
client.stop()
print("客户端已停止。")
网友评论