PyQt+socket實(shí)現(xiàn)遠(yuǎn)程操作服務(wù)器的方法示例
來需求了。。干活啦。。
需求內(nèi)容
部分時候由于緩存刷新、驗(yàn)證碼顯示不出來或者瀏覽器打不開或者打開速度很慢等原因,導(dǎo)致部分測試同事不想使用瀏覽器登錄服務(wù)器執(zhí)行命令。 期望有小工具可以替代登錄瀏覽器的操作,直接發(fā)送指令到服務(wù)器執(zhí)行并將執(zhí)行結(jié)果返回。
需求設(shè)計
1、開發(fā)界面,方便用戶輸入IP、用戶名、密碼以及執(zhí)行的命令。
2、IP、用戶名、密碼和命令輸入提供默認(rèn)值。特別是用戶名和密碼,對于測試服務(wù)器來說,通常都是固定的。
3、IP、命令行輸入框可以自動補(bǔ)全用戶輸入。自動補(bǔ)全常用IP、命令行可以提高操作效率。
4、可以自動保存用戶執(zhí)行成功的IP、命令行。用于完善自動補(bǔ)全命令(本文代碼未實(shí)現(xiàn))。
需求設(shè)計
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ā)。拖動4個label+4個輸入框+1個按鈕+1個textBrowser到主界面。開發(fā)后界面同需求設(shè)計中的截圖。
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):
"""
用戶初始化控件自動補(bǔ)全功能
"""
# 增加自動補(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、輸入框自動補(bǔ)全功能函數(shù)。同樣適用于下拉框控件。
def init_lineedit(self, lineedit, item_list):
"""
用戶初始化控件自動補(bǔ)全功能
"""
# 增加自動補(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編碼,否則會導(dǎo)致界面卡?。?/p>
sockethandle.sendall(send_cmd.encode('utf-8'))
3、需要將命令返回的內(nèi)容解碼再寫入文本框,否則會導(dǎo)致界面卡住。
recdata = sockethandle.recv(65535)
tran_recdata = recdata.decode('utf-8')
self.result_textBrowser.setText(tran_recdata)
附錄
由于本地沒有服務(wù)器用于調(diào)試程序。所以使用socket搭建1個建議服務(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()
啟動服務(wù)器:

簡陋的有點(diǎn)過分,但是滿足調(diào)試需求了。。。
小結(jié)
這個python+scoket需求實(shí)現(xiàn)的遠(yuǎn)程登錄服務(wù)器執(zhí)行命令只是把基本功能實(shí)現(xiàn)了。中間遇到的界面無響應(yīng)甚至退出的問題(就是socket發(fā)送和接收內(nèi)容編解碼導(dǎo)致的)。。但是還有很多地方需要優(yōu)化,比如對入?yún)⒌呐袛嗖⑤敵龅轿谋究蛱崾?、對連接服務(wù)器結(jié)果的判斷,還有界面的美化等內(nèi)容。。正是這些小需求及實(shí)踐過程中遇到問題、解決問題的過程逐步提升編碼能力。。fighting
相關(guān)文章
Python3.6簡單操作Mysql數(shù)據(jù)庫
這篇文章主要為大家詳細(xì)介紹了Python3.6簡單操作Mysql數(shù)據(jù)庫,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09
python日期時間轉(zhuǎn)為字符串或者格式化輸出的實(shí)例
今天小編就為大家分享一篇python日期時間轉(zhuǎn)為字符串或者格式化輸出的實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05
PyQt5入門之基于QListWidget版本實(shí)現(xiàn)圖片縮略圖列表功能
這篇文章主要介紹了PyQt5入門之基于QListWidget版本實(shí)現(xiàn)圖片縮略圖列表功能,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-09-09

