本項目旨在讓大家理解遠控軟體的原理,通過遠控桌面可以實現遠程控制我們的電腦,更好更方便的管理電腦。文末將給出初始版的完整代碼,需要使用到的其他工具也會有所說明。最終實現的效果就是只要用戶點擊了客戶端的程序運行,我們就可以在服務端對其進行控制。效果如下:左邊是客服端程序運行了,然後我們就可以在左邊的另一臺電腦上打開服務端程序進行控制,可以看到左邊的屏幕圖像也已經顯示在了右邊的電腦上。完整代碼見文末!
本次環境使用的是python3.6.5+windows平臺主要用的庫有:圖像處理庫opencv,包括用來目標檢測和圖像處理等操作。Numpy模塊用來輔助opencv對圖像進行一些像素值操作;pynput.mouse用來控制滑鼠點擊事件。達到遠程控制滑鼠的作用。客戶端在這裡指的是被控制的電腦,就是我們需要受到控制的電腦。1#客戶端代碼
2import socket
3import threading
4import cv2
5import numpy as np
6from PIL import ImageGrab
7from pynput.mouse import Button,Controller
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)
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#伺服器端
2import socket
3import threading
4import numpy as np
5import cv2
6import os
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()
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
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()
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
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)
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
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{background-color:rgb(78,255,255)}"
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 '''
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)
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)
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'遠程桌面')
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()
☞騰訊回應兩塊八賣《鬼谷八荒》:已下架並退款;iMac Pro 售完即停產;iCloud 識別姓氏鬧烏龍 | 極客頭條
☞騰訊:這可是一隻「骨骼清奇」的狗
☞《網際網路人求職圖鑑》:這類人才「最吃香」,最高薪程式語言出爐!
☞Google 重磅發布 Flutter 2 !一套代碼橫掃 5 大系統