PyQt+socket實(shí)現(xiàn)遠(yuǎn)程操作服務(wù)器的方法示例
來需求了。。干活啦。。
需求內(nèi)容
部分時(shí)候由于緩存刷新、驗(yàn)證碼顯示不出來或者瀏覽器打不開或者打開速度很慢等原因,導(dǎo)致部分測(cè)試同事不想使用瀏覽器登錄服務(wù)器執(zhí)行命令。 期望有小工具可以替代登錄瀏覽器的操作,直接發(fā)送指令到服務(wù)器執(zhí)行并將執(zhí)行結(jié)果返回。
需求設(shè)計(jì)
1、開發(fā)界面,方便用戶輸入IP、用戶名、密碼以及執(zhí)行的命令。
2、IP、用戶名、密碼和命令輸入提供默認(rèn)值。特別是用戶名和密碼,對(duì)于測(cè)試服務(wù)器來說,通常都是固定的。
3、IP、命令行輸入框可以自動(dòng)補(bǔ)全用戶輸入。自動(dòng)補(bǔ)全常用IP、命令行可以提高操作效率。
4、可以自動(dòng)保存用戶執(zhí)行成功的IP、命令行。用于完善自動(dòng)補(bǔ)全命令(本文代碼未實(shí)現(xiàn))。
需求設(shè)計(jì)
1、使用Qt Designer實(shí)現(xiàn)界面開發(fā)。開發(fā)后界面參考如下:

2、使用socket程序登錄服務(wù)器并執(zhí)行命令,并將結(jié)果顯示在界面文本框中。
代碼實(shí)現(xiàn)(程序可以直接復(fù)制運(yùn)行)
1、使用Qt Designer實(shí)現(xiàn)界面開發(fā)。拖動(dòng)4個(gè)label+4個(gè)輸入框+1個(gè)按鈕+1個(gè)textBrowser到主界面。開發(fā)后界面同需求設(shè)計(jì)中的截圖。
2、使用pyuic5 -o commandtools.py commandtools.ui指令將.ui文件轉(zhuǎn)換成.py文件。
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'commandTools.ui'
#
# Created by: PyQt5 UI code generator 5.11.3
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(483, 347)
self.ip_label = QtWidgets.QLabel(Form)
self.ip_label.setGeometry(QtCore.QRect(30, 20, 16, 16))
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.ip_label.setFont(font)
self.ip_label.setObjectName("ip_label")
self.ip_lineEdit = QtWidgets.QLineEdit(Form)
self.ip_lineEdit.setGeometry(QtCore.QRect(50, 20, 101, 20))
self.ip_lineEdit.setObjectName("ip_lineEdit")
self.username_label = QtWidgets.QLabel(Form)
self.username_label.setGeometry(QtCore.QRect(160, 20, 61, 16))
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.username_label.setFont(font)
self.username_label.setObjectName("username_label")
self.username_lineEdit = QtWidgets.QLineEdit(Form)
self.username_lineEdit.setGeometry(QtCore.QRect(220, 20, 71, 20))
self.username_lineEdit.setObjectName("username_lineEdit")
self.password_label = QtWidgets.QLabel(Form)
self.password_label.setGeometry(QtCore.QRect(300, 20, 61, 16))
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.password_label.setFont(font)
self.password_label.setObjectName("password_label")
self.password_lineEdit = QtWidgets.QLineEdit(Form)
self.password_lineEdit.setGeometry(QtCore.QRect(360, 20, 80, 20))
self.password_lineEdit.setObjectName("password_lineEdit")
self.command_label = QtWidgets.QLabel(Form)
self.command_label.setGeometry(QtCore.QRect(30, 70, 51, 16))
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.command_label.setFont(font)
self.command_label.setObjectName("command_label")
self.command_lineEdit = QtWidgets.QLineEdit(Form)
self.command_lineEdit.setGeometry(QtCore.QRect(90, 70, 251, 20))
self.command_lineEdit.setObjectName("command_lineEdit")
self.result_textBrowser = QtWidgets.QTextBrowser(Form)
self.result_textBrowser.setGeometry(QtCore.QRect(30, 120, 410, 201))
self.result_textBrowser.setObjectName("result_textBrowser")
self.run_Button = QtWidgets.QPushButton(Form)
self.run_Button.setGeometry(QtCore.QRect(360, 70, 80, 23))
self.run_Button.setObjectName("run_Button")
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "cmdTool"))
self.ip_label.setText(_translate("Form", "IP"))
self.ip_lineEdit.setText(_translate("Form", "127.0.0.1"))
self.username_label.setText(_translate("Form", "username"))
self.username_lineEdit.setText(_translate("Form", "admin"))
self.password_label.setText(_translate("Form", "password"))
self.password_lineEdit.setText(_translate("Form", "Winovs12!"))
self.command_label.setText(_translate("Form", "Command"))
self.command_lineEdit.setText(_translate("Form", "LST LOG"))
self.run_Button.setText(_translate("Form", "Run"))
3、實(shí)現(xiàn)主程序callcommand.py調(diào)用(業(yè)務(wù)與邏輯分離)。代碼如下:
# -*- coding: utf-8 -*-
import sys
import time
import socket
from PyQt5.QtWidgets import QApplication, QMainWindow,QCompleter
from PyQt5.QtCore import Qt,QThread,pyqtSignal
from commandTools import Ui_Form
class MyMainForm(QMainWindow, Ui_Form):
def __init__(self, parent=None):
"""
構(gòu)造函數(shù)
"""
super(MyMainForm, self).__init__(parent)
self.setupUi(self)
self.run_Button.clicked.connect(self.execte_command)
self.ip_init_lst = ['121.1.1.1', '192.168.1.1', '172.16.1.1']
self.init_lineedit(self.ip_lineEdit,self.ip_init_lst)
self.cmd_init_lst = ['LST LOG', 'LST PARA','MOD PARA']
self.init_lineedit(self.command_lineEdit,self.cmd_init_lst)
def init_lineedit(self, lineedit, item_list):
"""
用戶初始化控件自動(dòng)補(bǔ)全功能
"""
# 增加自動(dòng)補(bǔ)全
self.completer = QCompleter(item_list)
# 設(shè)置匹配模式 有三種: Qt.MatchStartsWith 開頭匹配(默認(rèn)) Qt.MatchContains 內(nèi)容匹配 Qt.MatchEndsWith 結(jié)尾匹配
self.completer.setFilterMode(Qt.MatchContains)
# 設(shè)置補(bǔ)全模式 有三種: QCompleter.PopupCompletion(默認(rèn)) QCompleter.InlineCompletion QCompleter.UnfilteredPopupCompletion
self.completer.setCompletionMode(QCompleter.PopupCompletion)
# 給lineedit設(shè)置補(bǔ)全器
lineedit.setCompleter(self.completer)
def execte_command(self):
"""
登錄服務(wù)器,并執(zhí)行命令
"""
ip, username, password, command = self.get_input_para()
print(type(ip))
sockethandle = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sockethandle.connect((str(ip), 6000))
send_cmd = "username: %s, admin: %s, command: %s" % (username, password, command)
print(send_cmd)
sockethandle.sendall(send_cmd.encode('utf-8'))
time.sleep(0.5)
recdata = sockethandle.recv(65535)
tran_recdata = recdata.decode('utf-8')
self.result_textBrowser.setText(tran_recdata)
def get_input_para(self):
"""
獲取用戶界面輸入
"""
ip = self.ip_lineEdit.text()
username = self.username_lineEdit.text()
password = self.password_lineEdit.text()
command = self.command_lineEdit.text()
return ip, username, password, command
if __name__ == "__main__":
app = QApplication(sys.argv)
myWin = MyMainForm()
myWin.show()
sys.exit(app.exec_())
4、使用pyinstaller轉(zhuǎn)換成可執(zhí)行的.exe文件。命令: pyinstaller -F callcommand.py -w


執(zhí)行成功,生成的文件在d:\temp\dist\dist\callcommand.exe
5、運(yùn)行callcommand.exe,點(diǎn)擊run運(yùn)行

關(guān)鍵代碼
1、輸入框自動(dòng)補(bǔ)全功能函數(shù)。同樣適用于下拉框控件。
def init_lineedit(self, lineedit, item_list):
"""
用戶初始化控件自動(dòng)補(bǔ)全功能
"""
# 增加自動(dòng)補(bǔ)全
self.completer = QCompleter(item_list)
# 設(shè)置匹配模式 有三種: Qt.MatchStartsWith 開頭匹配(默認(rèn)) Qt.MatchContains 內(nèi)容匹配 Qt.MatchEndsWith 結(jié)尾匹配
self.completer.setFilterMode(Qt.MatchContains)
# 設(shè)置補(bǔ)全模式 有三種: QCompleter.PopupCompletion(默認(rèn)) QCompleter.InlineCompletion QCompleter.UnfilteredPopupCompletion
self.completer.setCompletionMode(QCompleter.PopupCompletion)
# 給lineedit設(shè)置補(bǔ)全器
lineedit.setCompleter(self.completer)
2、socket中sendall函數(shù)要將命令使用utf-8編碼,否則會(huì)導(dǎo)致界面卡住:
sockethandle.sendall(send_cmd.encode('utf-8'))
3、需要將命令返回的內(nèi)容解碼再寫入文本框,否則會(huì)導(dǎo)致界面卡住。
recdata = sockethandle.recv(65535)
tran_recdata = recdata.decode('utf-8')
self.result_textBrowser.setText(tran_recdata)
附錄
由于本地沒有服務(wù)器用于調(diào)試程序。所以使用socket搭建1個(gè)建議服務(wù)器。服務(wù)器功能實(shí)現(xiàn)將接收的命令原樣返回。就是接收什么命令就給客戶端返回什么內(nèi)容。服務(wù)器IP為本地IP127.0.0.1,綁定端口為6000。代碼如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import socket
import sys
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print("socket create success!")
try:
s.bind(('127.0.0.1',6000))
except socket.error as msg:
print(msg)
sys.exit(1)
s.listen(10)
while True:
conn, addr = s.accept()
print("success")
data = conn.recv(65535)
conn.sendall(data.decode('utf-8'))
conn.close()
s.close()
啟動(dòng)服務(wù)器:

簡(jiǎn)陋的有點(diǎn)過分,但是滿足調(diào)試需求了。。。
小結(jié)
這個(gè)python+scoket需求實(shí)現(xiàn)的遠(yuǎn)程登錄服務(wù)器執(zhí)行命令只是把基本功能實(shí)現(xiàn)了。中間遇到的界面無響應(yīng)甚至退出的問題(就是socket發(fā)送和接收內(nèi)容編解碼導(dǎo)致的)。。但是還有很多地方需要優(yōu)化,比如對(duì)入?yún)⒌呐袛嗖⑤敵龅轿谋究蛱崾?、?duì)連接服務(wù)器結(jié)果的判斷,還有界面的美化等內(nèi)容。。正是這些小需求及實(shí)踐過程中遇到問題、解決問題的過程逐步提升編碼能力。。fighting
相關(guān)文章
Python實(shí)現(xiàn)批量將符合要求的文件自動(dòng)復(fù)制到新文件夾
這篇文章主要為大家詳細(xì)介紹了如何使用Python實(shí)現(xiàn)批量將文件名稱符合要求的文件自動(dòng)復(fù)制到新文件夾,文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考下2023-10-10
Python實(shí)現(xiàn)掃描指定目錄下的子目錄及文件的方法
這篇文章主要介紹了Python實(shí)現(xiàn)掃描指定目錄下的子目錄及文件的方法,需要的朋友可以參考下2014-07-07
numpy array找出符合條件的數(shù)并賦值的示例代碼
本文主要介紹了numpy array找出符合條件的數(shù)并賦值的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
基于Python實(shí)現(xiàn)實(shí)時(shí)監(jiān)控CPU使用率
這篇文章主要為大家介紹了一款手寫編程代碼的小腳本,能夠輕松在界面上展示:利用Python實(shí)時(shí)監(jiān)控CPU使用率,隨時(shí)展現(xiàn)。也無需下載管理軟件,感興趣的可以了解一下2022-04-04
Python?pyecharts?數(shù)據(jù)可視化模塊的配置方法
Echarts 是一個(gè)由百度開源的數(shù)據(jù)可視化,憑借著良好的交互性,精巧的圖表設(shè)計(jì),得到了眾多開發(fā)者的認(rèn)可,這篇文章主要介紹了Python?pyecharts?數(shù)據(jù)可視化模塊,需要的朋友可以參考下2022-09-09
python 命令行傳入?yún)?shù)實(shí)現(xiàn)解析
這篇文章主要介紹了python 命令行傳入?yún)?shù)實(shí)現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08

