Python實(shí)現(xiàn)局域網(wǎng)遠(yuǎn)程控制電腦
1.簡(jiǎn)介
一款由Python可以遠(yuǎn)程控制局域網(wǎng)電腦關(guān)機(jī)、重啟、注銷、鎖定 、休眠、退出登錄甚至能操作遠(yuǎn)程電腦Cmd終端命令的一款工具。資源及源碼已打包,大家可自行下載。
工具分為1.0以及2.0版本,2.0版本在1.0終端命令行模式更改為網(wǎng)頁(yè)界面化操作,可利用手機(jī)等多終端設(shè)備控制,更加美觀實(shí)用;優(yōu)化了端口設(shè)置,添加了條件判斷;可結(jié)合“Radmin_LAN”軟件,實(shí)現(xiàn)異地控制。工具可用Pyinstaller打包成無(wú)窗口后臺(tái)靜默運(yùn)行。
默認(rèn)賬號(hào):root
默認(rèn)密碼:123456
2. 運(yùn)行效果
1.0版本運(yùn)行效果:
2.0版本運(yùn)行效果:
PC端頁(yè)面效果:
服務(wù)端頁(yè)面:
客戶端登錄頁(yè)面:
客戶端操作頁(yè)面:
手機(jī)移動(dòng)端展示效果:
3. 1.0版本相關(guān)源碼
服務(wù)端server.py
import socket import keyboard import subprocess import threading import logging import queue ''' import win32gui import win32con # 獲取當(dāng)前窗口句柄 hwnd = win32gui.GetForegroundWindow() # 設(shè)置窗口屬性,隱藏窗口 win32gui.ShowWindow(hwnd, win32con.SW_HIDE) ''' # 配置日志 logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') print("客戶端登錄賬號(hào):root,密碼:123456,F(xiàn)3關(guān)閉服務(wù)器") print() ip1 = '192.168.137.1' # 默認(rèn)ip地址 print(f"請(qǐng)輸入服務(wù)器IP地址(電腦的IPv4地址),不輸入默認(rèn)為 {ip1}") # 超時(shí)設(shè)置,15秒 def get_input(prompt, timeout, result_queue): try: user_input = input(prompt) if user_input.strip() == "": result_queue.put(None) # 如果用戶直接回車,返回None else: result_queue.put(user_input) except Exception as e: logging.error(f"輸入過(guò)程中發(fā)生錯(cuò)誤: {e}") # 創(chuàng)建一個(gè)線程來(lái)獲取輸入 print("超時(shí)時(shí)間---15秒") print() result_queue = queue.Queue() input_thread = threading.Thread(target=get_input, args=("請(qǐng)輸入服務(wù)器IP地址:", 15, result_queue)) input_thread.start() # 等待輸入,如果超時(shí)則返回默認(rèn)值 input_thread.join(15) if not result_queue.empty(): ip = result_queue.get() if ip is None: ip = ip1 # 如果用戶直接回車,使用默認(rèn)值 else: ip = ip1 print(f"最終IP地址: {ip}") ''' def get_ipv4_address(): hostname = socket.gethostname() ip_address = socket.gethostbyname(hostname) return ip_address ip=get_ipv4_address() print(ip) ''' # 創(chuàng)建一個(gè) TCP/IP socket server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 設(shè)置 SO_REUSEADDR 選項(xiàng) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 綁定服務(wù)器地址和端口 server_address = (ip, 5000) server_socket.bind(server_address) # 監(jiān)聽(tīng)連接 server_socket.listen(5) # 支持最多5個(gè)并發(fā)連接 print('服務(wù)器正在等待連接...') def close_server(): print('服務(wù)器已關(guān)閉') server_socket.close() exit() # 監(jiān)聽(tīng) F3 鍵關(guān)閉服務(wù)器 keyboard.add_hotkey('F3', close_server) def handle_client(client_socket, client_address): try: print('連接來(lái)自:', client_address) # 接收賬號(hào)和密碼 data = client_socket.recv(1024) logging.debug(f"接收到的數(shù)據(jù): {data.decode()}") # 解析賬號(hào)和密碼 try: account, password = data.decode().split(':') except ValueError: logging.error("賬號(hào)和密碼格式錯(cuò)誤") message = '賬號(hào)和密碼格式錯(cuò)誤!' client_socket.send(message.encode()) return # 驗(yàn)證賬號(hào)和密碼 if account == 'root' and password == '123456': # 發(fā)送成功消息 message = '登錄成功!' client_socket.send(message.encode()) # 接收客戶端請(qǐng)求 while True: request = client_socket.recv(1024).decode() logging.debug(f"接收到的請(qǐng)求: {request}") if request == '1': # 關(guān)機(jī) subprocess.call('shutdown /s /t 0', shell=True) elif request == '2': # 重啟 subprocess.call('shutdown /r /t 0', shell=True) elif request == '3': # 休眠 subprocess.call('rundll32.exe powrprof.dll,SetSuspendState 0,1,0', shell=True) elif request == '4': # 鎖定 subprocess.call('rundll32.exe user32.dll,LockWorkStation', shell=True) elif request == '0': # 退出登錄 print(client_address, "退出登錄") break elif request == '5': # 等待用戶輸入 user_input = 1 while True: # 執(zhí)行cmd命令 command = client_socket.recv(1024).decode() logging.debug(f"接收到的命令:{command}") try: # 執(zhí)行命令 result = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) # 獲取命令的輸出 output, error = result.communicate() # 打印命令的輸出到本地控制臺(tái) logging.debug(f"{output}") # 發(fā)送命令的輸出 if error: output = " " client_socket.sendall(output.encode()) logging.debug(f"{error}") # 發(fā)送命令的錯(cuò)誤 client_socket.sendall(error.encode()) logging.debug("命令結(jié)果已發(fā)送") except subprocess.CalledProcessError as e: logging.error(f"{e.stderr}") # 發(fā)送錯(cuò)誤信息 client_socket.sendall(str(e).encode()) finally: # 發(fā)送一個(gè)結(jié)束標(biāo)記 client_socket.sendall(' '.encode()) # 等待用戶輸入 #接收客戶端的user_input值 user_input = client_socket.recv(1024).decode() logging.debug(f"接收到的請(qǐng)求: {user_input}") if user_input == '1': # 繼續(xù)執(zhí)行命令 continue elif user_input == '2': print(client_address, "退出登錄") # 退出循環(huán) break else: # 無(wú)效輸入 client_socket.sendall('無(wú)效輸入'.encode()) # 繼續(xù)執(zhí)行命令 continue else: # 無(wú)效輸入 client_socket.sendall('無(wú)效輸入'.encode()) else: # 無(wú)效請(qǐng)求 message = '無(wú)效請(qǐng)求!' client_socket.send(message.encode()) else: # 發(fā)送失敗消息 message = '賬號(hào)或密碼錯(cuò)誤!' client_socket.send(message.encode()) except Exception as e: logging.error(f"處理客戶端連接時(shí)發(fā)生錯(cuò)誤: {e}") finally: # 關(guān)閉連接 client_socket.close() while True: try: # 等待客戶端連接 client_socket, client_address = server_socket.accept() logging.debug(f"接受到來(lái)自 {client_address} 的連接") # 創(chuàng)建新線程處理客戶端連接 client_thread = threading.Thread(target=handle_client, args=(client_socket, client_address)) client_thread.start() except OSError as e: if e.errno == 10038: print('服務(wù)器已關(guān)閉') break else: raise input("按回車鍵退出...")
客戶端client.py
import socket def run_script(): try: print() ip1 = '192.168.137.1' print("請(qǐng)輸入服務(wù)器的IP地址,不輸入默認(rèn)ip為", ip1) print() ip = input("請(qǐng)輸入服務(wù)器的IP地址:") or ip1 print() # 服務(wù)器地址和端口 server_address = (ip, 5000) # 創(chuàng)建一個(gè) TCP/IP socket client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: # 連接到服務(wù)器 client_socket.connect(server_address) print('已連接到服務(wù)器') # 獲取用戶輸入的賬號(hào)和密碼 account = input('請(qǐng)輸入賬號(hào):') or 'root' password = input('請(qǐng)輸入密碼:') or '123456' # 發(fā)送賬號(hào)和密碼 message = f'{account}:{password}' client_socket.sendall(message.encode()) # 接收服務(wù)器響應(yīng) response = client_socket.recv(1024).decode() print('服務(wù)器響應(yīng):', response) if response == '登錄成功!': print('登錄成功') print() # 發(fā)送默認(rèn)請(qǐng)求 print("[0]退出登錄---[1]關(guān)機(jī)---[2]重啟---[3]休眠") print("[4]鎖定---[5]執(zhí)行cmd命令") print() request = input('輸入數(shù)字: ') or "5" # 你可以修改這個(gè)請(qǐng)求 if request in ['0', '1', '2', '3', '4', '5']: client_socket.sendall(request.encode()) print("請(qǐng)求已發(fā)送") if request == '0': print("退出登錄成功") elif request == '5': while True: # 獲取用戶輸入的命令 print() command = input('請(qǐng)輸入要執(zhí)行的命令:') or "echo %date% %time%" # 發(fā)送命令 client_socket.sendall(command.encode()) # 設(shè)置超時(shí)時(shí)間 client_socket.settimeout(60) try: print() print("接收超時(shí)時(shí)間為60秒") print() # 接收命令的輸出 data = b'' count = 0 while count < 2: packet = client_socket.recv(4096) data += packet count += 1 output = data.decode('utf-8', errors='ignore') print(output) except socket.timeout: print("接收命令的輸出超時(shí)") # 等待用戶輸入 print() user_input = input("是否繼續(xù)執(zhí)行命令?[1]繼續(xù)---[2]退出: ") or "1" if user_input == '1': # 發(fā)送 client_socket.sendall(user_input.encode()) # 繼續(xù)執(zhí)行命令 continue elif user_input == '2': print("退出登錄成功") break else: # 無(wú)效輸入 print('無(wú)效輸入,繼續(xù)執(zhí)行命令') # 發(fā)送 client_socket.sendall(user_input.encode()) # 繼續(xù)執(zhí)行命令 continue else: print("無(wú)效的請(qǐng)求") else: print('登錄失敗') finally: # 關(guān)閉連接 client_socket.close() user_choice = input("輸入1繼續(xù)運(yùn)行,輸入2結(jié)束代碼: ") if user_choice == '2': print("結(jié)束代碼") return elif user_choice == '1': print("繼續(xù)運(yùn)行") run_script() else: print("無(wú)效輸入,默認(rèn)退出代碼") except Exception as e: print(f"An error occurred: {e}") else: print("Script completed successfully.") run_script()
4. 2.0版本相關(guān)源碼
from flask import Flask, request, render_template_string, jsonify import subprocess import socket import os app = Flask(__name__) def get_local_ip(): try: with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s: # 連接到一個(gè)公網(wǎng)DNS服務(wù)器,不發(fā)送任何數(shù)據(jù),只是為了獲取本地IP s.connect(("8.8.8.8", 53)) return s.getsockname()[0] except: return None # 如果無(wú)法獲取IP,返回None def load_server_ip(): ip_file = 'server_ip.txt' if not os.path.exists(ip_file): return None with open(ip_file, 'r') as f: ip = f.read().strip() return ip if ip else None def save_server_ip(ip): ip_file = 'server_ip.txt' with open(ip_file, 'w') as f: f.write(ip) def ping_ip(ip): """ Ping指定的IP,返回True如果IP可達(dá),否則返回False """ try: # 在Windows系統(tǒng)上使用-4參數(shù)強(qiáng)制使用IPv4 output = subprocess.check_output(['ping', '-4', '-n', '1', ip], stderr=subprocess.STDOUT, universal_newlines=True) if "unreachable" in output.lower(): return False return True except subprocess.CalledProcessError: return False def bind_server(host_ip): try: print(f"嘗試綁定到IP: {host_ip}") app.run(host=host_ip, port=80) except Exception as e: print(f"綁定到 {host_ip} 失敗: {e}") return False return True def main(): # 嘗試從server_ip.txt讀取IP server_ip = load_server_ip() if server_ip: print(f"從文件加載服務(wù)器IP: {server_ip}") if not ping_ip(server_ip): print(f"Ping測(cè)試失敗,IP {server_ip} 不可用") server_ip = None else: print(f"Ping測(cè)試成功,IP {server_ip} 可用") else: server_ip = None # 重置server_ip,因?yàn)槲募淮嬖诨騼?nèi)容為空 # 如果server_ip.txt中的IP不可用,嘗試獲取本機(jī)IP if not server_ip: server_ip = get_local_ip() if server_ip: print(f"獲取到服務(wù)器IP: {server_ip}") if not ping_ip(server_ip): print(f"Ping測(cè)試失敗,IP {server_ip} 不可用") server_ip = None else: print(f"Ping測(cè)試成功,IP {server_ip} 可用") save_server_ip(server_ip) else: print("無(wú)法獲取本機(jī)IP") # 嘗試綁定到server_ip if server_ip: if not bind_server(server_ip): # 如果綁定失敗,嘗試綁定到127.0.0.1 print("綁定到指定IP失敗,嘗試綁定到127.0.0.1") if not bind_server('127.0.0.1'): print("綁定到127.0.0.1也失敗,終止腳本") exit(1) else: # 如果沒(méi)有有效的IP,嘗試綁定到127.0.0.1 print("沒(méi)有有效的IP,嘗試綁定到127.0.0.1") if not bind_server('127.0.0.1'): print("綁定到127.0.0.1失敗,終止腳本") exit(1) @app.route('/', methods=['GET', 'POST']) def login(): if request.method == 'POST': data = request.form if 'username' in data and 'password' in data: username = data['username'] password = data['password'] print(f"Received username: {username}, password: {password}") if username == 'root' and password == '123456': # 這里是用戶名和密碼,請(qǐng)自行修改。 return render_template_string(''' <!DOCTYPE html> <html> <head> <title>登錄成功</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> body { font-family: Arial, sans-serif; margin: 20px; } h1, h2 { text-align: center; } /* 按鈕樣式 */ .btn { padding: 10px 20px; font-size: 16px; margin: 5px; border: none; border-radius: 4px; cursor: pointer; background-color: #007bff; color: white; } .btn:hover { background-color: #0056b3; } /* 輸入框樣式 */ #command-input { width: 100%; height: 100px; font-size: 16px; padding: 10px; resize: vertical; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; } /* 結(jié)果顯示區(qū)域 */ #result { margin-top: 20px; padding: 10px; border: 1px solid #ddd; border-radius: 4px; background-color: #f9f9f9; white-space: pre-wrap; /* 保留換行 */ } /* 執(zhí)行按鈕樣式 */ #execute-button { float: right; margin-top: 10px; } /* 響應(yīng)式設(shè)計(jì) */ @media (max-width: 600px) { .btn { width: 100%; font-size: 14px; } #command-input { height: 100px; font-size: 14px; } #execute-button { width: 100%; float: none; } #result { font-size: 14px; } } </style> </head> <body> <h1>登錄成功</h1> <div style="text-align: center;"> <button class="btn">退出登錄</button> <button class="btn">關(guān)機(jī)</button> <button class="btn">重啟</button> <button class="btn">休眠</button> <button class="btn">鎖定</button> </div> <br> <h2>執(zhí)行命令</h2> <textarea id="command-input" placeholder="請(qǐng)輸入命令"></textarea> <button id="execute-button" class="btn">執(zhí)行</button> <h3>結(jié)果:</h3> <div id="result"></div> <script> function logout() { fetch('/logout', { method: 'GET' }) .then(response => response.json()) .then(data => { alert(data.message); window.location.href = '/'; }); } function shutdown() { fetch('/shutdown', { method: 'GET' }) .then(response => response.json()) .then(data => alert(data.message)); } function restart() { fetch('/restart', { method: 'GET' }) .then(response => response.json()) .then(data => alert(data.message)); } function sleep() { fetch('/sleep', { method: 'GET' }) .then(response => response.json()) .then(data => alert(data.message)); } function lock() { fetch('/lock', { method: 'GET' }) .then(response => response.json()) .then(data => alert(data.message)); } function executeCommand() { const command = document.getElementById('command-input').value; fetch('/execute', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ command: command }) }) .then(response => response.json()) .then(data => { document.getElementById('result').innerText = data.output; }) .catch(error => { document.getElementById('result').innerText = '執(zhí)行失敗'; }); } </script> </body> </html> ''') else: return jsonify({"message": "登錄失敗"}), 401 else: return jsonify({"message": "缺少用戶名或密碼"}), 400 else: return render_template_string(''' <!DOCTYPE html> <html> <head> <title>登錄</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> body { font-family: Arial, sans-serif; margin: 20px; } form { max-width: 400px; margin: 0 auto; } input[type="text"], input[type="password"] { width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; } input[type="submit"] { width: 100%; padding: 10px; background-color: #28a745; color: white; border: none; border-radius: 4px; cursor: pointer; } input[type="submit"]:hover { background-color: #218838; } @media (max-width: 600px) { form { max-width: 100%; } } </style> </head> <body> <h1>登錄</h1> <form method="post"> <input type="text" name="username" placeholder="用戶名"><br> <input type="password" name="password" placeholder="密碼"><br> <input type="submit" value="登錄"> </form> </body> </html> ''') @app.route('/logout', methods=['GET']) def logout(): return jsonify({"message": "退出登錄成功"}), 200 @app.route('/shutdown', methods=['GET']) def shutdown(): try: subprocess.run(["shutdown", "/s", "/t", "1"], check=True) return jsonify({"message": "關(guān)機(jī)成功"}), 200 except subprocess.CalledProcessError as e: return jsonify({"message": "關(guān)機(jī)失敗", "error": str(e)}), 500 @app.route('/restart', methods=['GET']) def restart(): try: subprocess.run(["shutdown", "/r", "/t", "1"], check=True) return jsonify({"message": "重啟成功"}), 200 except subprocess.CalledProcessError as e: return jsonify({"message": "重啟失敗", "error": str(e)}), 500 @app.route('/sleep', methods=['GET']) def sleep(): try: subprocess.run(["rundll32.exe", "powrprof.dll,SetSuspendState", "0,1,0"], check=True) return jsonify({"message": "休眠成功"}), 200 except subprocess.CalledProcessError as e: return jsonify({"message": "休眠失敗", "error": str(e)}), 500 @app.route('/lock', methods=['GET']) def lock(): try: subprocess.run(["rundll32", "user32.dll,LockWorkStation"], check=True) return jsonify({"message": "鎖定成功"}), 200 except subprocess.CalledProcessError as e: return jsonify({"message": "鎖定失敗", "error": str(e)}), 500 @app.route('/execute', methods=['POST']) def execute(): data = request.get_json() command = data.get('command', '') try: result = subprocess.run(command, shell=True, capture_output=True, text=True) output = result.stdout + result.stderr return jsonify({"output": output}), 200 except Exception as e: return jsonify({"output": f"執(zhí)行失敗: {str(e)}"}), 500 if __name__ == '__main__': main()
到此這篇關(guān)于Python實(shí)現(xiàn)局域網(wǎng)遠(yuǎn)程控制電腦的文章就介紹到這了,更多相關(guān)Python遠(yuǎn)程控制電腦內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Matplotlib繪制混淆矩陣的實(shí)現(xiàn)
對(duì)于機(jī)器學(xué)習(xí)多分類模型來(lái)說(shuō),其評(píng)價(jià)指標(biāo)除了精度之外,常用的還有混淆矩陣和分類報(bào)告,下面來(lái)展示一下如何繪制混淆矩陣,這在論文中經(jīng)常會(huì)用到。感興趣的可以了解一下2021-05-05python中對(duì)正則表達(dá)式re包的簡(jiǎn)單引用方式
這篇文章主要介紹了python中對(duì)正則表達(dá)式re包的簡(jiǎn)單引用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02Python?Traceback(most?recent?call?last)報(bào)錯(cuò)信息:示例解讀
這篇文章主要介紹了Python?Traceback(most?recent?call?last)報(bào)錯(cuò)信息:示例解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12修改默認(rèn)的pip版本為對(duì)應(yīng)python2.7的方法
今天小編就為大家分享一篇修改默認(rèn)的pip版本為對(duì)應(yīng)python2.7的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-11-11詳解Python中的魔法函數(shù)與量子計(jì)算模擬
這篇文章主要介紹了python的魔法函數(shù)和量子計(jì)算模擬,我們可以通過(guò)一個(gè)實(shí)際的案例來(lái)先審視一下這兩個(gè)需求是如何被結(jié)合起來(lái)的,希望對(duì)大家有所幫助2023-03-03Python利用函數(shù)式編程實(shí)現(xiàn)優(yōu)化代碼
函數(shù)式編程(Functional Programming)是一種編程范式,它將計(jì)算視為函數(shù)的求值,并且避免使用可變狀態(tài)和循環(huán),在Python中還可以利用它的簡(jiǎn)潔和高效來(lái)解決實(shí)際問(wèn)題,下面我們就來(lái)學(xué)習(xí)一下它的具體用法吧2023-11-11python四個(gè)坐標(biāo)點(diǎn)對(duì)圖片區(qū)域最小外接矩形進(jìn)行裁剪
在圖像裁剪操作中,opencv和pillow兩個(gè)庫(kù)都具有相應(yīng)的函數(shù),如果想要對(duì)目標(biāo)的最小外接矩形進(jìn)行裁剪該如何操作呢?本文就來(lái)詳細(xì)的介紹一下2021-06-06python數(shù)字圖像處理實(shí)現(xiàn)直方圖與均衡化
在圖像處理中,直方圖是非常重要,也是非常有用的一個(gè)處理要素。這篇文章主要介紹了python數(shù)字圖像處理實(shí)現(xiàn)直方圖與均衡化,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05