Python開(kāi)發(fā)多媒體管理軟件實(shí)現(xiàn)方法

軟件開(kāi)發(fā)環(huán)境

python 3.7.3
pycharm Community 2020

教師端控制界面

Server端界面
  • 下拉列表顯示全部已經(jīng)連接的客戶端ip地址。
  • 選中某個(gè)設(shè)備可查看設(shè)備信息,進(jìn)行重啟電腦,關(guān)閉電腦,鎖屏等操作。
  • 教師端具備廣播功能,可以自定義教師廣播的文本內(nèi)容。
  • 監(jiān)控所有已連接的學(xué)生端屏幕,可以點(diǎn)擊查看大圖。
  • 系統(tǒng)信息顯示欄,可以顯示教師端的IP地址和端口號(hào);顯示學(xué)生端設(shè)備信息,可以顯示對(duì)學(xué)生端電腦作出的重啟、關(guān)閉、鎖屏等。

學(xué)生端軟件界面

學(xué)生端軟件界面

學(xué)生端軟件包括如下內(nèi)容:

  • 連接教師端,需要輸入教師端的網(wǎng)址和端口號(hào)
  • 操作面板提示做的各項(xiàng)操作內(nèi)容和老師的廣播內(nèi)容
  • 可以向教師端傳輸文件,傳輸文件大小不超過(guò)1Mb
  • 舉手簽到操作,點(diǎn)擊舉手后教師端可以即時(shí)看到舉手信息

軟件技術(shù)規(guī)格:

1、軟件包括學(xué)生端和教師端,采用局域網(wǎng)通信。
2、教師端能夠連接至少2臺(tái)學(xué)生端。
3、學(xué)生端能夠向教師端發(fā)送文件。
4、學(xué)生端能夠進(jìn)行簽到舉手操作。
5、教師端能夠向?qū)W生端設(shè)備廣播信息,信息內(nèi)容可自定義。
6、教師端可以對(duì)學(xué)生端屏幕進(jìn)行查看。
7、教師端可以對(duì)學(xué)生端計(jì)算機(jī)進(jìn)行重啟操作。
8、教師端可以對(duì)學(xué)生端計(jì)算機(jī)進(jìn)行關(guān)閉操作。
9、教師端可以對(duì)學(xué)生端計(jì)算機(jī)進(jìn)行鎖屏操作。
10、教師端能夠接收學(xué)生端上傳的文件,狀態(tài)欄顯示自動(dòng)接收文件的信息。
11、教師端能夠查看學(xué)生端計(jì)算機(jī)的狀態(tài)如CPU占用, 狀態(tài)欄顯示狀態(tài)信息。
12、教師端能偶查看學(xué)生端的簽到舉手操作,從狀態(tài)欄顯示。

需求詳細(xì)分析

控制學(xué)生端,發(fā)送信息,發(fā)送文件,發(fā)送監(jiān)控視頻,都要基于數(shù)據(jù)傳輸。因此首先選定教師端和學(xué)生端的通信協(xié)議為T(mén)CP/IP。
1、基于此通信協(xié)議后,教師端需要接收:客戶端的信息,舉手信息,設(shè)備狀態(tài),文件;
2、需要發(fā)送:自定義廣播內(nèi)容,重啟、關(guān)機(jī)、鎖屏等命令。相對(duì)于教師端的接收和操作,每個(gè)學(xué)生端就應(yīng)具備相應(yīng)的發(fā)送和接收功能。
3、教師端對(duì)學(xué)生端屏幕監(jiān)控功能。學(xué)生端需要具備靜默運(yùn)行的屏幕截取功能,并發(fā)送到服務(wù)端。服務(wù)端能夠接收到全部已經(jīng)連接的學(xué)生端截屏,并顯示在屏幕上。

軟件架構(gòu)

應(yīng)用架構(gòu)

根據(jù)以上的需求分析,軟件的架構(gòu)框圖如下圖所示。


服務(wù)端軟件架構(gòu)

軟件在界面的支撐下,需要實(shí)現(xiàn)TCP服務(wù)端和監(jiān)控端的功能。TCP服務(wù)器具備相應(yīng)的接收和發(fā)送功能。教師端的監(jiān)控功能持續(xù)接收學(xué)生端的屏幕截圖。

服務(wù)端框圖詳細(xì)設(shè)計(jì)

在軟件架構(gòu)的指導(dǎo)下,我們將軟件分為以上多條線實(shí)現(xiàn),包括了Server開(kāi)啟,接收Client的信息,并能夠發(fā)送信息;接收屏幕截圖。所有邏輯運(yùn)行的線路,用多線程方式運(yùn)行,邏輯線程同界面線程分離,避免界面假死,提高界面的友好度。

數(shù)據(jù)傳輸?shù)脑?/h5>

TCP傳輸?shù)脑砜梢詤⒄站W(wǎng)絡(luò)相關(guān)資料。如下是TCP進(jìn)行傳輸?shù)娜挝帐诌^(guò)程說(shuō)明。

TCP三次握手的過(guò)程如下:
客戶端發(fā)送SYN(SEQ=x)報(bào)文給服務(wù)器端,進(jìn)入SYN_SEND狀態(tài)。
服務(wù)器端收到SYN報(bào)文,回應(yīng)一個(gè)SYN (SEQ=y)ACK(ACK=x+1)報(bào)文,進(jìn)入SYN_RECV狀態(tài)。
客戶端收到服務(wù)器端的SYN報(bào)文,回應(yīng)一個(gè)ACK(ACK=y+1)報(bào)文,進(jìn)入Established狀態(tài)。

屏幕截圖的原理

python進(jìn)行屏幕截圖,采用pyautogui對(duì)屏幕進(jìn)行截取,并使用HTTPServer來(lái)發(fā)送屏幕截圖。
pyautogui是對(duì)屏幕、鼠標(biāo)、鍵盤(pán)進(jìn)行控制的python庫(kù),調(diào)用screenshot()將返回Image對(duì)象,該screenshot()功能大約需要100毫秒。
如果你不需要截取整個(gè)屏幕,還有一個(gè)可選的region參數(shù)。你可以把截取區(qū)域的左上角XY坐標(biāo)值和寬度、高度傳入截取。其文檔位于https://pyautogui.readthedocs.io/en/latest/。

http server就是web server,或者說(shuō)網(wǎng)頁(yè)服務(wù)器,網(wǎng)站服務(wù)器。常用的web server有iis,apache等。iis是internet information server的簡(jiǎn)稱,是windows上主要的web服務(wù)器。

界面開(kāi)發(fā)基礎(chǔ)

PYQT5開(kāi)發(fā)的方法。采用QtDesigner來(lái)簡(jiǎn)單設(shè)計(jì)一個(gè)界面,并保存為一個(gè)文件名為ui的文件。
如下提供了一個(gè)python調(diào)用ui文件并顯示出界面的方法。

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        loadUi("ui_source_server/server_panel.ui", self)  # 加載面板文件,使用qt designer開(kāi)發(fā)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.setStyleSheet(qss_style)
    window.show()
    sys.exit(app.exec_())

如果希望對(duì)軟件界面進(jìn)行美化,那么就在main中加入qss文件。qss是類似于CSS的文件,下文將做出解釋。

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    with open('style_source_server/app_style.qss', encoding='utf-8') as f:
        qss_style = f.read()
    window.setStyleSheet(qss_style)
    window.show()
    sys.exit(app.exec_())

實(shí)現(xiàn)路徑

1、界面初步實(shí)現(xiàn)


教師端的初步實(shí)現(xiàn)

學(xué)生端的初步實(shí)現(xiàn)

2、屏幕錄制
采用PyAutoGUI.screenshot()完成屏幕截圖。
HTTPServer提供截圖頁(yè)面。

from http.server import BaseHTTPRequestHandler, HTTPServer
import PyAutoGUI
import socket
PORT = 8008
# 獲取學(xué)生機(jī)局域網(wǎng)地址
IP = socket.gethostbyname(socket.gethostname())
#windows
class myHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        img = PyAutoGUI.screenshot() #屏幕截圖
        if img:
            self.send_response(200) #HTTP 狀態(tài)碼
            self.send_header('Content-Type', 'image/png')
            self.end_headers()
            img.save(self.wfile, 'PNG') # 寫(xiě)入HTTP 響應(yīng)流文件


def main():
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        #判斷當(dāng)前端口是否已經(jīng)打開(kāi)
        result = sock.connect_ex((IP, PORT))
        portopen = result == 0
        sock.close()
        if not portopen:
            #啟動(dòng)web服務(wù)器,用自定義的響應(yīng)處理類
            server = HTTPServer((IP, PORT), myHandler)
            server.serve_forever() # 服務(wù)器持續(xù)監(jiān)聽(tīng)
    except:
        pass

if __name__ == '__main__':
    main()

如果單獨(dú)運(yùn)行屏幕截取的程序后,在瀏覽器中打開(kāi)localhost:8008,就能立刻看到截取的屏幕圖像了。如果手動(dòng)刷新頁(yè)面,截取的屏幕圖像也隨之刷新。

  1. 連接上后端的數(shù)據(jù)
    教師的服務(wù)端程序可以連接上學(xué)生端的屏幕圖像,再設(shè)置輪詢以后就可以顯示截屏了。該種方法實(shí)現(xiàn)的屏幕監(jiān)控具有弊端,在總結(jié)部分有解釋。


    界面上顯示后端的
eval('self.video_' + str(i + 1)).setPixmap(video)

在pyqt5中使用setPixmap將圖片顯示到label中。

4.軟件界面和邏輯的分離
python中如果采用PYQT5開(kāi)發(fā)界面,強(qiáng)烈推薦使用多線程來(lái)開(kāi)發(fā)界面和邏輯分離的部分。如下中self.check_thread來(lái)開(kāi)啟多線程程序,程序的回調(diào)信號(hào)為pyqtSignal。回調(diào)信號(hào)的參數(shù)類型可以是python自帶的常規(guī)函數(shù)類型,如int,string,list等,如果是其他更復(fù)雜的類型,可以存放到list類型中進(jìn)行傳遞。
多線程的函數(shù)返回值觸發(fā)回調(diào)函數(shù),如下self.server_callback?;卣{(diào)函數(shù)的參數(shù)value即回調(diào)信號(hào)的參數(shù)。

        self.check_thread = Server([])  # 多線程去獲取
        self.check_thread.signal.connect(self.server_callback)
        self.check_thread.start()  # 啟動(dòng)線程
class Server(QThread):
    signal = pyqtSignal(list)  # 括號(hào)里填寫(xiě)信號(hào)傳遞的參數(shù)

    def __init__(self, args_list):
        super().__init__()
        self.args_data = args_list

    def __del__(self):
        self.wait()

    def run(self):
        while True:
            client_socket, client_address = socket_server.accept()
            if client_address not in conn_list:
                conn_list.append(client_address)
                conn_dt[client_address] = client_socket
            self.signal.emit([client_socket, client_address])  # 發(fā)射信號(hào)
    def server_callback(self, value):
        """
        Sever 回調(diào)函數(shù)功能
        :param value:
        :return:
        """

5.子窗口的實(shí)現(xiàn)
點(diǎn)擊每個(gè)學(xué)生端的查看按鈕,可以對(duì)學(xué)生端的屏幕進(jìn)行詳細(xì)查看。
父窗口連接子窗口。

self.child = Child(students[client_num - 1])  # 創(chuàng)建子窗口實(shí)例
self.child.exec()

傳入一個(gè)參數(shù),參數(shù)信息為當(dāng)前查看的學(xué)生信息。

class Child(QDialog):
    """
    查看客戶端詳情頁(yè)。
    """
    def __init__(self, label, parent=None):
        super().__init__(parent)
        self.student = label
        self.initUI()

    def initUI(self):
        loadUi("ui_source_server/child_panel.ui", self)
        self.setWindowTitle("多媒體管理軟件 -櫻桃智庫(kù)")  # 設(shè)置窗口標(biāo)題
        self.pushButton_quit.clicked.connect(self.quit)  # 點(diǎn)擊ok,隱士存在該方法

        self.timer = QTimer(self)  # 初始化一個(gè)定時(shí)器
        if self.student:
            self.timer.timeout.connect(self.get_client_screen)  # 每次計(jì)時(shí)到時(shí)間時(shí)發(fā)出信號(hào)
            self.timer.start(600)  # 設(shè)置計(jì)時(shí)間隔并啟動(dòng);單位毫秒
        else:
            pass

    def get_client_screen(self):
        self._thread = AutoPollScreen([self.student])  # 多線程去獲取
        self._thread.signal.connect(self.screen_callback)
        self._thread.start()  # 啟動(dòng)線程

    def screen_callback(self, videos):
        video = videos[0].scaled(1200, 800)
        self.label.setPixmap(video)

    def quit(self):  # 點(diǎn)擊ok是發(fā)送內(nèi)置信號(hào)
        self.timer.stop()
        self.close()

開(kāi)發(fā)完畢

最后的界面

其實(shí)可以更進(jìn)一步地對(duì)界面的美化進(jìn)行提高,但想想也沒(méi)必要了!


套娃的屏幕監(jiān)控

異常捕獲

1、屏幕截圖慢。
教師控制端采用輪詢的方式連接學(xué)生端的http服務(wù)器,會(huì)導(dǎo)致屏幕監(jiān)控出現(xiàn)卡頓或者幀數(shù)較慢的情況出現(xiàn)。針對(duì)此問(wèn)題的解決辦法可以借鑒騰訊會(huì)議的屏幕分享功能。

2、學(xué)生端關(guān)閉程序,教師端會(huì)卡死。
這個(gè)問(wèn)題主要是因?yàn)門(mén)CP的連接造成的,TCP連接成功后應(yīng)該主動(dòng)斷開(kāi)連接,否則會(huì)拋出異常。但是存在的難點(diǎn)是,如果學(xué)生端非正常退出,也沒(méi)有辦法將退出信號(hào)提前發(fā)送給教師端。

參考資料

暫無(wú)。

項(xiàng)目地址

https://github.com/Jarrettluo/multimedia_management_software

以上項(xiàng)目作為聯(lián)系項(xiàng)目,距離真正商用還有很遠(yuǎn)的距離。僅提供畢業(yè)設(shè)計(jì)或軟件開(kāi)發(fā)的參考項(xiàng)目。如果對(duì)其他的實(shí)現(xiàn)方法感興趣,我們可以從開(kāi)源地址聯(lián)系我,我們共同探討!

歡迎點(diǎn)贊、轉(zhuǎn)發(fā)、分享!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容