python实现远程桌面

2023-06-14,

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

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实现远程桌面.doc》

下载本文的Word格式文档,以方便收藏与打印。