python實現遠程桌面


項目旨在讓大家理解遠控軟件的原理,通過遠控桌面可以實現遠程控制我們的電腦,更好更方便的管理電腦。文末將給出初始版的完整代碼,需要使用到的其他工具也會有所說明。最終實現的效果就是只要用戶點擊了客戶端的程序運行,我們就可以在服務端對其進行控制。效果如下:左邊是客服端程序運行了,然后我們就可以在左邊的另一台電腦上打開服務端程序進行控制,可以看到左邊的屏幕圖像也已經顯示在了右邊的電腦上。完整代碼見文末!

 

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>=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.  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM