python实现远程桌面
项目旨在让大家理解远控软件的原理,通过远控桌面可以实现远程控制我们的电脑,更好更方便的管理电脑。文末将给出初始版的完整代码,需要使用到的其他工具也会有所说明。最终实现的效果就是只要用户点击了客户端的程序运行,我们就可以在服务端对其进行控制。效果如下:左边是客服端程序运行了,然后我们就可以在左边的另一台电脑上打开服务端程序进行控制,可以看到左边的屏幕图像也已经显示在了右边的电脑上。完整代码见文末!
01
远控流程
1.1 环境要求
本次环境使用的是python3.6.5+windows平台
主要用的库有:图像处理库opencv,包括用来目标检测和图像处理等操作。
Socket用来远程传输数据达到远程控制的效果;
Threading模块用来创建多线程管理;
Numpy模块用来辅助opencv对图像进行一些像素值操作;
PIL模块用来获取屏幕图像数据;
pynput.mouse用来控制鼠标点击事件。达到远程控制鼠标的作用。
1.2 客户端讲解
客户端在这里指的是被控制的电脑,就是我们需要受到控制的电脑。
(1)首先是导入相关模块:
- 1#客户端代码
- 2import socket
- 3import threading
- 4import cv2
- 5import numpy as np
- 6from PIL import ImageGrab
- 7from pynput.mouse import Button,Controller
(2)接着创建一个鼠标控制器和用来接收服务端数据的函数。因为需要一直都接收数据,故需要嵌入循环。在这里客户端还需要接收数据的原因是,用来接收服务端传来的鼠标控制信息,要不然怎么实现鼠标控制桌面的效果呢。
- 1#接受服务器返回的数据的函数
- 2m = Controller()
- 3def recvlink(client):
- 4 while True:
- 5 msg=client.recv(1024)
- 6 msg=msg.decode('utf-8')
- 7 print(msg)
- 8 key = msg.split(",")
- 9 xp = int(key[0])
- 10 yp = int(key[1])
- 11 m.position = ((xp,yp))
- 12 m.click(Button.left,1)
(3)创建ipv4的socket对象,使用TCP协议(SOCK_STREAM)。然后设置服务端IP地址,以及端口。这里用来向服务端传输数据,即传输桌面图像数据。注释代码如下:
- 1#创建ipv4的socket对象,使用TCP协议(SOCK_STREAM)
- 2client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- 3#设置服务器ip地址,注意应该是服务器的公网ip
- 4host='服务器的公网ip'
- 5#设置要发送到的服务器端口,需要在云服务器管理界面打开对应端口的防火墙
- 6port=设置的端口
- 7#建立TCP协议连接,这时候服务器就会监听到到连接请求,并开始等待接受client发送的数据
- 8client.connect((host,port))
- 9#建立连接后,服务器端会返回连接成功消息
- 10start_msg=client.recv(1024)
- 11print(start_msg.decode('utf-8'))
- 12#开启一个线程用来接受服务器发来的消息
- 13t=threading.Thread(target=recvlink,args=(client,))
- 14t.start()
- 15p = ImageGrab.grab()#获得当前屏幕
- 16quality = 25 # 图像的质量
- 17encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), quality]
- 18while True:
- 19 im = ImageGrab.grab()
- 20 imm=cv2.cvtColor(np.array(im), cv2.COLOR_RGB2BGR)#转为opencv的BGR格式
- 21 imm = cv2.resize(imm, (1535, 863))
- 22 img_encode = cv2.imencode(".jpg", imm, encode_param)[1]
- 23 data_encode = np.array(img_encode)
- 24 str_encode = data_encode.tostring()
- 25 #print(len(str_encode))
- 26 #输入要发送的信息
- 27 sendmsg="kehu"
- 28 #向服务器发送消息
- 29 client.send(str_encode)
- 30 if sendmsg=='quit':
- 31 break
- 32#结束时关闭客户端
- 33client.close()
1.3 服务端讲解
服务端指的是用来控制远程电脑的那一端,为了方便使用,我们直接在服务器上使用即可。
(1)导入使用到的模块:
- 1#服务器端
- 2import socket
- 3import threading
- 4import numpy as np
- 5import cv2
- 6import os
(2)创建鼠标点击事件函数,用来获取鼠标点击的位置坐标:
- 1print("等待连接---")
- 2def mouse_click(event, x, y, flags, para):
- 3 if event == cv2.EVENT_LBUTTONDOWN: # 左边鼠标点击
- 4 f=open("1.txt","w")
- 5 f.write(str(x)+","+str(y))
- 6 f.close()
(3)创建服务器端接收数据函数,用来实时接收传输过来的图像数据并显示:
- 1def recv_msg(clientsocket):
- 2 while True:
- 3 # 接受客户端消息,设置一次最多接受10240字节的数据
- 4 recv_msg = clientsocket.recv(102400)
- 5 # 把接收到的东西解码
- 6 msg = np.fromstring(recv_msg, np.uint8)
- 7 img_decode = cv2.imdecode(msg, cv2.IMREAD_COLOR)
- 8 try:
- 9 s=img_decode.shape
- 10 img_decode=img_decode
- 11 temp=img_decode
- 12 except:
- 13 img_decode=temp
- 14 pass
- 15 cv2.imshow('SERVER', img_decode)
- 16 cv2.setMouseCallback("SERVER", mouse_click)
- 17 try:
- 18 f=open("1.txt")
- 19 txt=f.read()
- 20 f.close()
- 21 reply=txt
- 22 print(reply)
- 23 clientsocket.send(reply.encode('utf-8'))
- 24 os.remove("1.txt")
- 25 except:
- 26 pass
- 27 if cv2.waitKey(1) & 0xFF == ord('q'):
- 28 break
(4)主函数,用来建立连接和数据接收等功能。
- 1def main():
- 2 socket_server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- 3 host='服务器的本地ip'
- 4 #设置被监听的端口号,小于1024的端口号不能使用
- 5 port=设置的端口
- 6 socket_server.bind((host,port))
- 7 #设置最大监听数,也就是最多可以同时响应几个客户端请求,一般配合多线程使用
- 8 socket_server.listen(5)
- 9 #等待客户端连接,一旦有了连接就立刻向下执行,否则等待
- 10 #accept()函数会返回一个元组,第一个元素是客户端socket对象,第二个元素是客户端地址(ip地址+端口号)
- 11 clientsocket,addr=socket_server.accept()
- 12 # 有了客户端连接后之后才能执行以下代码,我们先向客户端发送连接成功消息
- 13 clientsocket.send('连接成功'.encode('utf-8'))
- 14 # 和客户端一样开启一个线程接受客户端的信息
- 15 t=threading.Thread(target=recv_msg,args=(clientsocket,))
- 16 t.start()
02
远程控制GUI窗口
远控桌面GUI主要是为了美观而用,需要大家根据远程代码进行集合修改。当然单独使用上述代码已经可以实现功能了,只是不够美观。由于考虑到此处代码量较大,且不是重点,故粗略讲解
(1)导入相关库:
- 1from PyQt5.QtWidgets import *
- 2from PyQt5.QtCore import *
- 3from PyQt5.QtGui import QPalette, QBrush, QPixmap
- 4import os
- 5import socket
- 6import threading
- 7import cv2
- 8import numpy as np
- 9from PIL import ImageGrab
- 10from pynput.mouse import Button,Controller
- 11import time
(2)建立鼠标控制函数和点击函数
- 1m = Controller()
- 2def mouse_click(event, x, y, flags, para):
- 3 if event == cv2.EVENT_LBUTTONDOWN: # 左边鼠标点击
- 4 print( x, y)
- 5 m.position = (x, y)
- 6 time.sleep(0.1)
- 7 m.click(Button.left, 1)
(3)GUI界面初始化,由于我们需要把实时的视频显示在窗口上,故也需要使用到opencv。
- 1def __init__(self, parent=None):
- 2 super(Ui_MainWindow, self).__init__(parent)
- 3 # self.face_recong = face.Recognition()
- 4 self.timer_camera = QtCore.QTimer()
- 5 self.cap = cv2.VideoCapture()
- 6 self.CAM_NUM = 0
- 7 self.set_ui()
- 8 self.slot_init()
- 9 self.__flag_work = 0
- 10 self.x = 0
- 11 self.count = 0
(4)设置窗口大小和控件位置等信息。创建布局和设置名称
- 1def set_ui(self):
- 2 self.__layout_main = QtWidgets.QHBoxLayout()
- 3 self.__layout_fun_button = QtWidgets.QVBoxLayout()
- 4 self.__layout_data_show = QtWidgets.QVBoxLayout()
- 5 self.button_open_camera = QtWidgets.QPushButton(u'远程桌面')
- 6 self.button_close = QtWidgets.QPushButton(u'退出')
- 7 # Button 的颜色修改
- 8 button_color = [self.button_open_camera, self.button_close]
- 9 for i in range(2):
- 10 button_color[i].setStyleSheet("QPushButton{color:black}"
- 11 "QPushButton:hover{color:red}"
- 12 "QPushButton{ outline: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; list-style: none; overflow-wrap: break-word; height: 22px;">13 "QPushButton{border:2px}"
- 14 "QPushButton{border-radius:10px}"
- 15 "QPushButton{padding:2px 4px}")
- 16 self.button_open_camera.setMinimumHeight(50)
- 17 self.button_close.setMinimumHeight(50)
- 18 # move()方法移动窗口在屏幕上的位置到x = 300,y = 300坐标。
- 19 self.move(500, 500)
- 20 # 信息显示
- 21 self.label_show_camera = QtWidgets.QLabel()
- 22 self.label_move = QtWidgets.QLabel()
- 23 self.label_move.setFixedSize(100, 100)
- 24 self.label_show_camera.setFixedSize(1530,863)
- 25 self.label_show_camera.setAutoFillBackground(False)
- 26 self.__layout_fun_button.addWidget(self.button_open_camera)
- 27 self.__layout_fun_button.addWidget(self.button_close)
- 28 self.__layout_fun_button.addWidget(self.label_move)
- 29 self.__layout_main.addLayout(self.__layout_fun_button)
- 30 self.__layout_main.addWidget(self.label_show_camera)
- 31 self.setLayout(self.__layout_main)
- 32 self.label_move.raise_()
- 33 self.setWindowTitle(u'远控桌面GUI')
- 34 '''
- 35 # 设置背景图片
- 36 palette1 = QPalette()
- 37 palette1.setBrush(self.backgroundRole(), QBrush(QPixmap('background.jpg')))
- 38 self.setPalette(palette1)
- 39 '''
(5)获取鼠标点击时的坐标:
- 1def mousePressEvent(self,event):
- 2 if event.buttons() & QtCore.Qt.LeftButton:
- 3 x = event.x()-120
- 4 y = event.y()-10
- 5 text = "x: {0},y: {1}".format(x,y)
- 6 if x>=0 and y>=0:
- 7 m.position = (x, y)
- 8 time.sleep(0.1)
- 9 m.click(Button.left, 1)
- 10 print(text)
(6)按钮绑定所设置的函数:
- 1def slot_init(self):
- 2 self.button_open_camera.clicked.connect(self.button_open_camera_click)
- 3 self.timer_camera.timeout.connect(self.show_camera)
- 4 self.button_close.clicked.connect(self.close)
(7)显示桌面功能函数,并设置点击时修改名称,可以随时关闭桌面
- 1def button_open_camera_click(self):
- 2 if self.timer_camera.isActive() == False:
- 3 self.timer_camera.start(30)
- 4 self.button_open_camera.setText(u'关闭')
- 5 else:
- 6 self.timer_camera.stop()
- 7 self.cap.release()
- 8 self.label_show_camera.clear()
- 9 self.button_open_camera.setText(u'远程桌面')
(8)显示桌面函数和退出程序函数
- 1def show_camera(self):
- 2 im = ImageGrab.grab()
- 3 imm = cv2.cvtColor(np.array(im), cv2.COLOR_RGB2BGR) # 转为opencv的BGR格式
- 4 #imm = cv2.resize(imm, (1535, 863))
- 5 self.image = imm
- 6 # face = self.face_detect.align(self.image)
- 7 # if face:
- 8 # pass
- 9 show =cv2.resize(self.image, (1536,863))
- 10 show = cv2.cvtColor(show, cv2.COLOR_BGR2RGB)
- 11 print(show.shape[1], show.shape[0])
- 12 # show.shape[1] = 640, show.shape[0] = 480
- 13 showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0], QtGui.QImage.Format_RGB888)
- 14 self.label_show_camera.setPixmap(QtGui.QPixmap.fromImage(showImage))
- 15 #cv2.setMouseCallback(showImage, mouse_click)
- 16 # self.x += 1
- 17 # self.label_move.move(self.x,100)
- 18 # if self.x ==320:
- 19 # self.label_show_camera.raise_()
- 20def closeEvent(self, event):
- 21 ok = QtWidgets.QPushButton()
- 22 cacel = QtWidgets.QPushButton()
- 23 msg = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Warning, u"关闭", u"是否关闭!")
- 24 msg.addButton(ok, QtWidgets.QMessageBox.ActionRole)
- 25 msg.addButton(cacel, QtWidgets.QMessageBox.RejectRole)
- 26 ok.setText(u'确定')
- 27 cacel.setText(u'取消')
- 28 # msg.setDetailedText('sdfsdff')
- 29 if msg.exec_() == QtWidgets.QMessageBox.RejectRole:
- 30 event.ignore()
- 31 else:
- 32 # self.socket_client.send_command(self.socket_client.current_user_command)
- 33 if self.cap.isOpened():
- 34 self.cap.release()
- 35 if self.timer_camera.isActive():
- 36 self.timer_camera.stop()
- 37 event.accept()
python实现远程桌面的更多相关文章
- Python 远程桌面协议RDPY简介
转载请注明:@小五义http://www.cnblogs.com/xiaowuyiQQ群:64770604 RDPY 是基于 Twisted Python 实现的微软 RDP 远程桌面协议. RDPY ...
- 【一步一步走(1)】远程桌面软件VNC的安装与配置
近期在VPS上搭建Python Web环境.走了非常多弯路,借此记下. 先说说购买的VPS(PhotonVPS),我可不是打广告.仅仅是感觉这个VPS服务提供商还不错推荐给你大家,我之前也是体验过阿里 ...
- 远程桌面MATLAB启动失败问题解决
博客:博客园 | CSDN | blog 远程桌面打开MATLAB会报错,解决办法,打开matlab的licenses路径,如matlab/R2017b/licenses/,路径下存有license文 ...
- Centos-Redhat下远程桌面的方法 & Redhat改Centos源
折腾了好几天才搞定,Redhat下远程桌面的方法,首先保证本身已经装了桌面,并且可以ssh访问 由于系统中自带python2环境,装了anaconda以及它带的python3环境,这个必须存在(前提) ...
- FRP+WoL实现远程开机+远程桌面
FRP+WoL实现远程开机+远程桌面 故事背景 这是一个很复杂而且很久远的故事,如果要讲的话,这个故事可以追溯到1981年(「都是废话,没有干货,如果不感兴趣请从第二章开始」),简单来说: 1981年 ...
- Python编写的桌面图形界面程序实现更新检测和下载安装
在Python中我们有很多种方案来编写桌面图形用户界面程序,譬如内置的 Tkinter .强大的 PyQt5 和 PySide2 ,还有 wxPython .借助这些或内置或第三方的模块,我们可以轻松 ...
- CentOS 6.8 安装TigerVNC 实现 Linux 远程桌面
CentOS 6.8 有默认的安装的 vnc 位于端口 5900 : 系统->首选项->远程桌面 勾选[共享]的选项, 取消勾选[安全]的选项, 然后防火墙添加 5900 端口 基本就可 ...
- [No00008B]远程桌面发送“Ctrl+Alt+Delete”组合键调用任务管理器
向远程桌面发送"Ctrl+Alt+Delete"组合键的两种方法 1.在本地按下Ctrl+Alt+End,可以成功发送"Ctrl+Alt+Delete"组合键! ...
- 远程桌面时plsql的复制粘贴功能失效
解决办法:重新启动远程桌面上的rdpclip进程就可以复制粘贴了,但是每次重开远程桌面都会出现同样的问题.可以rdpclip这个设置成开机启动.
- QQ远程桌面的使用
腾讯QQ怎样使用远程桌面: ---------------------- ----------------------
随机推荐
- scanf 读入 string 注意点
在做题的时候需要读入字符串,但是又不想使用char 数组,于是采用string存储,当时遇到了scanf读取string失败,查阅资料后总结下. scanf是c的标准输入输出流,想要读入string, ...
- 消息队列 RocketMQ4.x介绍和新概念讲解
消息队列 RocketMQ4.x介绍和新概念讲解 Apache RocketMQ作为阿里开源的一款高性能.高吞吐量的分布式消息中间件 RocketMQ4.x特点 支持Broker和Consumer端消 ...
- Websocket是什么?
一. WebSocket是什么? Websocket是一种网络通信协议,是一个在计算机里专门在[两点]之间传输数据的约定和规范. 二. 为什么存在WebSocket? 因为 HTTP 协议有一个缺陷: ...
- 【基础知识】C++算法基础(快速排序)
快速排序: 1.执行流程(一趟快排): 2.一趟快排的结果:获得一个枢纽,在此左边皆小于此数,在此右边皆大于此数,因此可以继续使用递归获得最终的序列.
- 实验5 开源控制器实践——POX
实验5 开源控制器实践--POX 一.实验目的 1.能够理解 POX 控制器的工作原理: 2.通过验证POX的forwarding.hub和forwarding.l2_learning模块,初步掌握P ...
- FHAdmin实战获取shell
又是一个愉快的摸鱼的一天,闲来无事去逛先知社区突然看到了一篇名为shrio权限实战绕过的文章(https://xz.aliyun.com/t/8311),这时不禁突然 回想起来之前看到过的一个微信公众 ...
- C语言编译概念理解
1.编译与CPU.操作系统的联系 参考:https://blog.csdn.net/dong_daxia/article/details/95328479?ops_request_misc=%257B ...
- java获取类内容
java获取类内容 Book类 public class Book implements Serializable { private int id; private String name; pri ...
- centos 添加yum源失败,ping 百度没响应
1. curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.r ...
- Mapper method 'org.lin.hms.dao.IndentDAO.insertIndent' has an unsupported return type: interface java.util.List
出现这种错误,说明sql语句执行成功,只是返回类型出了问题. 解决办法: mapper文件中的update,delete,insert语句是不需要设置返回类型的,它们都是默认返回一个int ,所以把返 ...