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

2、使用socket程序登錄服務器并執(zhí)行命令,并將結果顯示在界面文本框中。
代碼實現(程序可以直接復制運行)
1、使用Qt Designer實現界面開發(fā)。拖動4個label+4個輸入框+1個按鈕+1個textBrowser到主界面。開發(fā)后界面同需求設計中的截圖。
2、使用pyuic5 -o commandtools.py commandtools.ui指令將.ui文件轉換成.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、實現主程序callcommand.py調用(業(yè)務與邏輯分離)。代碼如下:
# -*- 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):
"""
構造函數
"""
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):
"""
用戶初始化控件自動補全功能
"""
# 增加自動補全
self.completer = QCompleter(item_list)
# 設置匹配模式 有三種: Qt.MatchStartsWith 開頭匹配(默認) Qt.MatchContains 內容匹配 Qt.MatchEndsWith 結尾匹配
self.completer.setFilterMode(Qt.MatchContains)
# 設置補全模式 有三種: QCompleter.PopupCompletion(默認) QCompleter.InlineCompletion QCompleter.UnfilteredPopupCompletion
self.completer.setCompletionMode(QCompleter.PopupCompletion)
# 給lineedit設置補全器
lineedit.setCompleter(self.completer)
def execte_command(self):
"""
登錄服務器,并執(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轉換成可執(zhí)行的.exe文件。命令: pyinstaller -F callcommand.py -w


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

關鍵代碼
1、輸入框自動補全功能函數。同樣適用于下拉框控件。
def init_lineedit(self, lineedit, item_list):
"""
用戶初始化控件自動補全功能
"""
# 增加自動補全
self.completer = QCompleter(item_list)
# 設置匹配模式 有三種: Qt.MatchStartsWith 開頭匹配(默認) Qt.MatchContains 內容匹配 Qt.MatchEndsWith 結尾匹配
self.completer.setFilterMode(Qt.MatchContains)
# 設置補全模式 有三種: QCompleter.PopupCompletion(默認) QCompleter.InlineCompletion QCompleter.UnfilteredPopupCompletion
self.completer.setCompletionMode(QCompleter.PopupCompletion)
# 給lineedit設置補全器
lineedit.setCompleter(self.completer)
2、socket中sendall函數要將命令使用utf-8編碼,否則會導致界面卡?。?/p>
sockethandle.sendall(send_cmd.encode('utf-8'))
3、需要將命令返回的內容解碼再寫入文本框,否則會導致界面卡住。
recdata = sockethandle.recv(65535)
tran_recdata = recdata.decode('utf-8')
self.result_textBrowser.setText(tran_recdata)
附錄
由于本地沒有服務器用于調試程序。所以使用socket搭建1個建議服務器。服務器功能實現將接收的命令原樣返回。就是接收什么命令就給客戶端返回什么內容。服務器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()
啟動服務器:

簡陋的有點過分,但是滿足調試需求了。。。
小結
這個python+scoket需求實現的遠程登錄服務器執(zhí)行命令只是把基本功能實現了。中間遇到的界面無響應甚至退出的問題(就是socket發(fā)送和接收內容編解碼導致的)。。但是還有很多地方需要優(yōu)化,比如對入參的判斷并輸出到文本框提示、對連接服務器結果的判斷,還有界面的美化等內容。。正是這些小需求及實踐過程中遇到問題、解決問題的過程逐步提升編碼能力。。fighting
相關文章
PyQt5入門之基于QListWidget版本實現圖片縮略圖列表功能
這篇文章主要介紹了PyQt5入門之基于QListWidget版本實現圖片縮略圖列表功能,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-09-09

