项目旨在让大家理解远控软件的原理,通过远控桌面可以实现远程控制我们的电脑,更好更方便的管理电脑。文末将给出初始版的完整代码,需要使用到的其他工具也会有所说明。最终实现的效果就是只要用户点击了客户端的程序运行,我们就可以在服务端对其进行控制。效果如下:左边是客服端程序运行了,然后我们就可以在左边的另一台电脑上打开服务端程序进行控制,可以看到左边的屏幕图像也已经显示在了右边的电脑上。完整代码见文末!

01

远控流程

1.1 环境要求

本次环境使用的是python3.6.5+windows平台

主要用的库有:图像处理库opencv,包括用来目标检测和图像处理等操作。

Socket用来远程传输数据达到远程控制的效果;

Threading模块用来创建多线程管理;

Numpy模块用来辅助opencv对图像进行一些像素值操作;

PIL模块用来获取屏幕图像数据;

pynput.mouse用来控制鼠标点击事件。达到远程控制鼠标的作用。

1.2 客户端讲解

客户端在这里指的是被控制的电脑,就是我们需要受到控制的电脑。

(1)首先是导入相关模块:

  1.  
    1#客户端代码
  2.  
    2import socket
  3.  
    3import threading
  4.  
    4import cv2
  5.  
    5import numpy as np
  6.  
    6from PIL import ImageGrab
  7.  
    7from pynput.mouse import Button,Controller

(2)接着创建一个鼠标控制器和用来接收服务端数据的函数。因为需要一直都接收数据,故需要嵌入循环。在这里客户端还需要接收数据的原因是,用来接收服务端传来的鼠标控制信息,要不然怎么实现鼠标控制桌面的效果呢。

  1.  
    1#接受服务器返回的数据的函数
  2.  
    2m = Controller()
  3.  
    3def recvlink(client):
  4.  
    4    while True:
  5.  
    5        msg=client.recv(1024)
  6.  
    6        msg=msg.decode('utf-8')
  7.  
    7        print(msg)
  8.  
    8        key = msg.split(",")
  9.  
    9        xp = int(key[0])
  10.  
    10        yp = int(key[1])
  11.  
    11        m.position = ((xp,yp))
  12.  
    12        m.click(Button.left,1)
  13.  
     

(3)创建ipv4的socket对象,使用TCP协议(SOCK_STREAM)。然后设置服务端IP地址,以及端口。这里用来向服务端传输数据,即传输桌面图像数据。注释代码如下:

  1.  
    1#创建ipv4的socket对象,使用TCP协议(SOCK_STREAM)
  2.  
    2client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  3.  
    3#设置服务器ip地址,注意应该是服务器的公网ip
  4.  
    4host='服务器的公网ip'
  5.  
    5#设置要发送到的服务器端口,需要在云服务器管理界面打开对应端口的防火墙
  6.  
    6port=设置的端口
  7.  
    7#建立TCP协议连接,这时候服务器就会监听到到连接请求,并开始等待接受client发送的数据
  8.  
    8client.connect((host,port))
  9.  
    9#建立连接后,服务器端会返回连接成功消息
  10.  
    10start_msg=client.recv(1024)
  11.  
    11print(start_msg.decode('utf-8'))
  12.  
    12#开启一个线程用来接受服务器发来的消息
  13.  
    13t=threading.Thread(target=recvlink,args=(client,))
  14.  
    14t.start()
  15.  
    15p = ImageGrab.grab()#获得当前屏幕
  16.  
    16quality = 25  # 图像的质量
  17.  
    17encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), quality]
  18.  
    18while True:
  19.  
    19    im = ImageGrab.grab()
  20.  
    20    imm=cv2.cvtColor(np.array(im), cv2.COLOR_RGB2BGR)#转为opencv的BGR格式
  21.  
    21    imm = cv2.resize(imm, (1535, 863))
  22.  
    22    img_encode = cv2.imencode(".jpg", imm, encode_param)[1]
  23.  
    23    data_encode = np.array(img_encode)
  24.  
    24    str_encode = data_encode.tostring()
  25.  
    25    #print(len(str_encode))
  26.  
    26    #输入要发送的信息
  27.  
    27    sendmsg="kehu"
  28.  
    28    #向服务器发送消息
  29.  
    29    client.send(str_encode)
  30.  
    30    if sendmsg=='quit':
  31.  
    31        break
  32.  
    32#结束时关闭客户端
  33.  
    33client.close()
  34.  
     

1.3 服务端讲解

服务端指的是用来控制远程电脑的那一端,为了方便使用,我们直接在服务器上使用即可。

(1)导入使用到的模块:

  1.  
    1#服务器端
  2.  
    2import socket
  3.  
    3import threading
  4.  
    4import numpy as np
  5.  
    5import cv2
  6.  
    6import os
  7.  
     

(2)创建鼠标点击事件函数,用来获取鼠标点击的位置坐标:

  1.  
    1print("等待连接---")
  2.  
    2def mouse_click(event, x, y, flags, para):
  3.  
    3    if event == cv2.EVENT_LBUTTONDOWN:  # 左边鼠标点击
  4.  
    4        f=open("1.txt","w")
  5.  
    5        f.write(str(x)+","+str(y))
  6.  
    6        f.close()
  7.  
     

(3)创建服务器端接收数据函数,用来实时接收传输过来的图像数据并显示:

  1.  
    1def recv_msg(clientsocket):
  2.  
    2    while True:
  3.  
    3        # 接受客户端消息,设置一次最多接受10240字节的数据
  4.  
    4        recv_msg = clientsocket.recv(102400)
  5.  
    5        # 把接收到的东西解码
  6.  
    6        msg = np.fromstring(recv_msg, np.uint8)
  7.  
    7        img_decode = cv2.imdecode(msg, cv2.IMREAD_COLOR)
  8.  
    8        try:
  9.  
    9            s=img_decode.shape
  10.  
    10            img_decode=img_decode
  11.  
    11            temp=img_decode
  12.  
    12        except:
  13.  
    13            img_decode=temp
  14.  
    14            pass
  15.  
    15        cv2.imshow('SERVER', img_decode)
  16.  
    16        cv2.setMouseCallback("SERVER", mouse_click)
  17.  
    17        try:
  18.  
    18            f=open("1.txt")
  19.  
    19            txt=f.read()
  20.  
    20            f.close()
  21.  
    21            reply=txt
  22.  
    22            print(reply)
  23.  
    23            clientsocket.send(reply.encode('utf-8'))
  24.  
    24            os.remove("1.txt")
  25.  
    25        except:
  26.  
    26            pass
  27.  
    27        if cv2.waitKey(1) & 0xFF == ord('q'):
  28.  
    28            break
  29.  
     

(4)主函数,用来建立连接和数据接收等功能。

  1.  
    1def main():
  2.  
    2    socket_server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  3.  
    3    host='服务器的本地ip'
  4.  
    4    #设置被监听的端口号,小于1024的端口号不能使用
  5.  
    5    port=设置的端口
  6.  
    6    socket_server.bind((host,port))
  7.  
    7    #设置最大监听数,也就是最多可以同时响应几个客户端请求,一般配合多线程使用
  8.  
    8    socket_server.listen(5)
  9.  
    9    #等待客户端连接,一旦有了连接就立刻向下执行,否则等待
  10.  
    10    #accept()函数会返回一个元组,第一个元素是客户端socket对象,第二个元素是客户端地址(ip地址+端口号)
  11.  
    11    clientsocket,addr=socket_server.accept()
  12.  
    12    # 有了客户端连接后之后才能执行以下代码,我们先向客户端发送连接成功消息
  13.  
    13    clientsocket.send('连接成功'.encode('utf-8'))
  14.  
    14    # 和客户端一样开启一个线程接受客户端的信息
  15.  
    15    t=threading.Thread(target=recv_msg,args=(clientsocket,))
  16.  
    16    t.start()
  17.  
     

02

远程控制GUI窗口

远控桌面GUI主要是为了美观而用,需要大家根据远程代码进行集合修改。当然单独使用上述代码已经可以实现功能了,只是不够美观。由于考虑到此处代码量较大,且不是重点,故粗略讲解

(1)导入相关库:

  1.  
    1from PyQt5.QtWidgets import *
  2.  
    2from PyQt5.QtCore import *
  3.  
    3from PyQt5.QtGui import QPalette, QBrush, QPixmap
  4.  
    4import os
  5.  
    5import socket
  6.  
    6import threading
  7.  
    7import cv2
  8.  
    8import numpy as np
  9.  
    9from PIL import ImageGrab
  10.  
    10from pynput.mouse import Button,Controller
  11.  
    11import time
  12.  
     

(2)建立鼠标控制函数和点击函数

  1.  
    1m = Controller()
  2.  
    2def mouse_click(event, x, y, flags, para):
  3.  
    3    if event == cv2.EVENT_LBUTTONDOWN:  # 左边鼠标点击
  4.  
    4        print( x, y)
  5.  
    5        m.position = (x, y)
  6.  
    6        time.sleep(0.1)
  7.  
    7        m.click(Button.left, 1)
  8.  
     

(3)GUI界面初始化,由于我们需要把实时的视频显示在窗口上,故也需要使用到opencv。

  1.  
    1def __init__(self, parent=None):
  2.  
    2    super(Ui_MainWindow, self).__init__(parent)
  3.  
    3    # self.face_recong = face.Recognition()
  4.  
    4    self.timer_camera = QtCore.QTimer()
  5.  
    5    self.cap = cv2.VideoCapture()
  6.  
    6    self.CAM_NUM = 0
  7.  
    7    self.set_ui()
  8.  
    8    self.slot_init()
  9.  
    9    self.__flag_work = 0
  10.  
    10    self.x = 0
  11.  
    11    self.count = 0
  12.  
     

(4)设置窗口大小和控件位置等信息。创建布局和设置名称

  1.  
    1def set_ui(self):
  2.  
    2    self.__layout_main = QtWidgets.QHBoxLayout()
  3.  
    3    self.__layout_fun_button = QtWidgets.QVBoxLayout()
  4.  
    4    self.__layout_data_show = QtWidgets.QVBoxLayout()
  5.  
    5    self.button_open_camera = QtWidgets.QPushButton(u'远程桌面')
  6.  
    6    self.button_close = QtWidgets.QPushButton(u'退出')
  7.  
    7    # Button 的颜色修改
  8.  
    8    button_color = [self.button_open_camera, self.button_close]
  9.  
    9    for i in range(2):
  10.  
    10        button_color[i].setStyleSheet("QPushButton{color:black}"
  11.  
    11                                      "QPushButton:hover{color:red}"
  12.  
    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}"
  13.  
    14                                      "QPushButton{border-radius:10px}"
  14.  
    15                                      "QPushButton{padding:2px 4px}")
  15.  
    16    self.button_open_camera.setMinimumHeight(50)
  16.  
    17    self.button_close.setMinimumHeight(50)
  17.  
    18    # move()方法移动窗口在屏幕上的位置到x = 300,y = 300坐标。
  18.  
    19    self.move(500, 500)
  19.  
    20    # 信息显示
  20.  
    21    self.label_show_camera = QtWidgets.QLabel()
  21.  
    22    self.label_move = QtWidgets.QLabel()
  22.  
    23    self.label_move.setFixedSize(100, 100)
  23.  
    24    self.label_show_camera.setFixedSize(1530,863)
  24.  
    25    self.label_show_camera.setAutoFillBackground(False)
  25.  
    26    self.__layout_fun_button.addWidget(self.button_open_camera)
  26.  
    27    self.__layout_fun_button.addWidget(self.button_close)
  27.  
    28    self.__layout_fun_button.addWidget(self.label_move)
  28.  
    29    self.__layout_main.addLayout(self.__layout_fun_button)
  29.  
    30    self.__layout_main.addWidget(self.label_show_camera)
  30.  
    31    self.setLayout(self.__layout_main)
  31.  
    32    self.label_move.raise_()
  32.  
    33    self.setWindowTitle(u'远控桌面GUI')
  33.  
    34    '''
  34.  
    35    # 设置背景图片
  35.  
    36    palette1 = QPalette()
  36.  
    37    palette1.setBrush(self.backgroundRole(), QBrush(QPixmap('background.jpg')))
  37.  
    38    self.setPalette(palette1)
  38.  
    39    '''
  39.  
     

(5)获取鼠标点击时的坐标:

  1.  
    1def mousePressEvent(self,event):
  2.  
    2    if event.buttons() & QtCore.Qt.LeftButton:
  3.  
    3        x = event.x()-120
  4.  
    4        y = event.y()-10
  5.  
    5        text = "x: {0},y: {1}".format(x,y)
  6.  
    6        if x>=0 and y>=0:
  7.  
    7            m.position = (x, y)
  8.  
    8            time.sleep(0.1)
  9.  
    9            m.click(Button.left, 1)
  10.  
    10        print(text)
  11.  
     

(6)按钮绑定所设置的函数:

  1.  
    1def slot_init(self):
  2.  
    2    self.button_open_camera.clicked.connect(self.button_open_camera_click)
  3.  
    3    self.timer_camera.timeout.connect(self.show_camera)
  4.  
    4    self.button_close.clicked.connect(self.close)
  5.  
     

(7)显示桌面功能函数,并设置点击时修改名称,可以随时关闭桌面

  1.  
    1def button_open_camera_click(self):
  2.  
    2    if self.timer_camera.isActive() == False:
  3.  
    3        self.timer_camera.start(30)
  4.  
    4        self.button_open_camera.setText(u'关闭')
  5.  
    5    else:
  6.  
    6        self.timer_camera.stop()
  7.  
    7        self.cap.release()
  8.  
    8        self.label_show_camera.clear()
  9.  
    9        self.button_open_camera.setText(u'远程桌面')
  10.  
     

(8)显示桌面函数和退出程序函数

  1.  
    1def show_camera(self):
  2.  
    2    im = ImageGrab.grab()
  3.  
    3    imm = cv2.cvtColor(np.array(im), cv2.COLOR_RGB2BGR)  # 转为opencv的BGR格式
  4.  
    4    #imm = cv2.resize(imm, (1535, 863))
  5.  
    5    self.image = imm
  6.  
    6    # face = self.face_detect.align(self.image)
  7.  
    7    # if face:
  8.  
    8    #     pass
  9.  
    9    show =cv2.resize(self.image, (1536,863))
  10.  
    10    show = cv2.cvtColor(show, cv2.COLOR_BGR2RGB)
  11.  
    11    print(show.shape[1], show.shape[0])
  12.  
    12    # show.shape[1] = 640, show.shape[0] = 480
  13.  
    13    showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0], QtGui.QImage.Format_RGB888)
  14.  
    14    self.label_show_camera.setPixmap(QtGui.QPixmap.fromImage(showImage))
  15.  
    15    #cv2.setMouseCallback(showImage, mouse_click)
  16.  
    16    # self.x += 1
  17.  
    17    # self.label_move.move(self.x,100)
  18.  
    18    # if self.x ==320:
  19.  
    19    #     self.label_show_camera.raise_()
  20.  
    20def closeEvent(self, event):
  21.  
    21    ok = QtWidgets.QPushButton()
  22.  
    22    cacel = QtWidgets.QPushButton()
  23.  
    23    msg = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Warning, u"关闭", u"是否关闭!")
  24.  
    24    msg.addButton(ok, QtWidgets.QMessageBox.ActionRole)
  25.  
    25    msg.addButton(cacel, QtWidgets.QMessageBox.RejectRole)
  26.  
    26    ok.setText(u'确定')
  27.  
    27    cacel.setText(u'取消')
  28.  
    28    # msg.setDetailedText('sdfsdff')
  29.  
    29    if msg.exec_() == QtWidgets.QMessageBox.RejectRole:
  30.  
    30        event.ignore()
  31.  
    31    else:
  32.  
    32        #             self.socket_client.send_command(self.socket_client.current_user_command)
  33.  
    33        if self.cap.isOpened():
  34.  
    34            self.cap.release()
  35.  
    35        if self.timer_camera.isActive():
  36.  
    36            self.timer_camera.stop()
  37.  
    37        event.accept()
  38.  

python实现远程桌面的更多相关文章

  1. Python 远程桌面协议RDPY简介

    转载请注明:@小五义http://www.cnblogs.com/xiaowuyiQQ群:64770604 RDPY 是基于 Twisted Python 实现的微软 RDP 远程桌面协议. RDPY ...

  2. 【一步一步走(1)】远程桌面软件VNC的安装与配置

    近期在VPS上搭建Python Web环境.走了非常多弯路,借此记下. 先说说购买的VPS(PhotonVPS),我可不是打广告.仅仅是感觉这个VPS服务提供商还不错推荐给你大家,我之前也是体验过阿里 ...

  3. 远程桌面MATLAB启动失败问题解决

    博客:博客园 | CSDN | blog 远程桌面打开MATLAB会报错,解决办法,打开matlab的licenses路径,如matlab/R2017b/licenses/,路径下存有license文 ...

  4. Centos-Redhat下远程桌面的方法 & Redhat改Centos源

    折腾了好几天才搞定,Redhat下远程桌面的方法,首先保证本身已经装了桌面,并且可以ssh访问 由于系统中自带python2环境,装了anaconda以及它带的python3环境,这个必须存在(前提) ...

  5. FRP+WoL实现远程开机+远程桌面

    FRP+WoL实现远程开机+远程桌面 故事背景 这是一个很复杂而且很久远的故事,如果要讲的话,这个故事可以追溯到1981年(「都是废话,没有干货,如果不感兴趣请从第二章开始」),简单来说: 1981年 ...

  6. Python编写的桌面图形界面程序实现更新检测和下载安装

    在Python中我们有很多种方案来编写桌面图形用户界面程序,譬如内置的 Tkinter .强大的 PyQt5 和 PySide2 ,还有 wxPython .借助这些或内置或第三方的模块,我们可以轻松 ...

  7. CentOS 6.8 安装TigerVNC 实现 Linux 远程桌面

    CentOS 6.8 有默认的安装的 vnc 位于端口 5900 : 系统->首选项->远程桌面 勾选[共享]的选项,  取消勾选[安全]的选项, 然后防火墙添加 5900 端口 基本就可 ...

  8. [No00008B]远程桌面发送“Ctrl+Alt+Delete”组合键调用任务管理器

    向远程桌面发送"Ctrl+Alt+Delete"组合键的两种方法 1.在本地按下Ctrl+Alt+End,可以成功发送"Ctrl+Alt+Delete"组合键! ...

  9. 远程桌面时plsql的复制粘贴功能失效

    解决办法:重新启动远程桌面上的rdpclip进程就可以复制粘贴了,但是每次重开远程桌面都会出现同样的问题.可以rdpclip这个设置成开机启动.

  10. QQ远程桌面的使用

    腾讯QQ怎样使用远程桌面: ---------------------- ----------------------

随机推荐

  1. ubuntu | virtualbox报错:不能为虚拟电脑打开一个新任务

    百度了几个办法 都不行. 还得是gxd,说在vmware虚拟机设置勾上这个就行了

  2. 狐漠漠养成日记 Cp.00001 开始养成计划

    开始养成计划 今天是我开始这个"狐漠漠养成计划"的第一天(划掉). 看来是昨天出门前忘记保存了,昨天写的几百字内容全都没有了,今天其实已经是计划开始的第二天了. 因为昨天晚上出去喝 ...

  3. 实验1 Python开发环境使用和编程初体验

    # print输出的几种用法 # 用法1:用于输出单个字符串或单个变量 print('hey, u') # 用法2: 用于输出多个数据项,用逗号分隔 print('hey', ' u') x,y,z ...

  4. LeetCode 刷题感想之动态规划

    在 LeetCode/剑指Offer 上刷了500题左右了,应该写一篇文章总结一下自己的感想.因为我自己是测试,所以从测试角度来写感受吧. 先说动态规划. 什么是动态规划?是经典算法思想之一,是自底向 ...

  5. 2020ccpc威海C.Rencontre题解(树形dp)

    题目大意:给定一棵带边权树,给三份点的集合U1,U2,U3,求0.5*(E(dis(u1,u2))+E(dis(u1,u3))+E(dis(u2,u3))). 即,我们需要维护两份点的所有距离和.显然 ...

  6. ubuntu14.04 网络配置ubuntu14.04 网络配置

    流程分析: 在Ubuntu系统网络设备启动的流程中,会依赖/etc/network/interface的配置文件初始化网络接口,所以直接在/etc/network/interface之中配置好对应的d ...

  7. node express框架搭建

    前面了解了一些node.js的服务建立及事件绑定和触发,要想一步一步自己来写所有响应,还是比较麻烦,看了express,很多东西都由框架自动完成,开发人员仅需关注自己想要实现的功能即可,真正实现了让开 ...

  8. 语法分析~LL1的实现

    语法分析之 LL1分析法实现 一.设计目的 根据某一文法编制调试LL(1)分析程序,以便对任意输入的符号串进行分析.本次实验的目的主要是加深对预测分析LL(1)分析法的理解. 二.设计要求 程序输入/ ...

  9. LINUX下的VSCODE-C/C++配置

    LINUX下的VSCODE-C/C++配置 1.生成默认的任务文件 2.lunch.json,调整"configurations"里的成员,如下 ①添加 "preLaun ...

  10. C++初识指针之一

    新手学习C/C++都跳不过去的地方,就是指针,用的话,确实好用,但是概念比较绕, 指针的通俗说法 1.简单的来说,就是说每一个变量,在电脑内都占一个地方,这个地方用一个16进掉的编号来进行标记,类似于 ...