PyQt+socket实现远程操作服务器的方法示例


Posted in Python onAugust 22, 2019

来需求了。。干活啦。。

需求内容

部分时候由于缓存刷新、验证码显示不出来或者浏览器打不开或者打开速度很慢等原因,导致部分测试同事不想使用浏览器登录服务器执行命令。 期望有小工具可以替代登录浏览器的操作,直接发送指令到服务器执行并将执行结果返回。

需求设计

1、开发界面,方便用户输入IP、用户名、密码以及执行的命令。

2、IP、用户名、密码和命令输入提供默认值。特别是用户名和密码,对于测试服务器来说,通常都是固定的。

3、IP、命令行输入框可以自动补全用户输入。自动补全常用IP、命令行可以提高操作效率。

4、可以自动保存用户执行成功的IP、命令行。用于完善自动补全命令(本文代码未实现)。

需求设计

1、使用Qt Designer实现界面开发。开发后界面参考如下:

PyQt+socket实现远程操作服务器的方法示例

2、使用socket程序登录服务器并执行命令,并将结果显示在界面文本框中。

代码实现(程序可以直接复制运行)

1、使用Qt Designer实现界面开发。拖动4个label+4个输入框+1个按钮+1个textBrowser到主界面。开发后界面同需求设计中的截图。

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调用(业务与逻辑分离)。代码如下:

# -*- 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):
    """
    登录服务器,并执行命令
    """
    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转换成可执行的.exe文件。命令: pyinstaller -F callcommand.py -w

PyQt+socket实现远程操作服务器的方法示例

PyQt+socket实现远程操作服务器的方法示例

执行成功,生成的文件在d:\temp\dist\dist\callcommand.exe

5、运行callcommand.exe,点击run运行

PyQt+socket实现远程操作服务器的方法示例

关键代码

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编码,否则会导致界面卡住:

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()

启动服务器:

PyQt+socket实现远程操作服务器的方法示例

简陋的有点过分,但是满足调试需求了。。。

小结

这个python+scoket需求实现的远程登录服务器执行命令只是把基本功能实现了。中间遇到的界面无响应甚至退出的问题(就是socket发送和接收内容编解码导致的)。。但是还有很多地方需要优化,比如对入参的判断并输出到文本框提示、对连接服务器结果的判断,还有界面的美化等内容。。正是这些小需求及实践过程中遇到问题、解决问题的过程逐步提升编码能力。。fighting

Python 相关文章推荐
Python浅拷贝与深拷贝用法实例
May 09 Python
python安装cx_Oracle模块常见问题与解决方法
Feb 21 Python
python select.select模块通信全过程解析
Sep 20 Python
python中文乱码不着急,先看懂字节和字符
Dec 20 Python
Python2和Python3的共存和切换使用
Apr 12 Python
python处理“
Jun 10 Python
Python整数与Numpy数据溢出问题解决
Sep 11 Python
如何使用Python多线程测试并发漏洞
Dec 18 Python
Python应用实现处理excel数据过程解析
Jun 19 Python
Python3中小括号()、中括号[]、花括号{}的区别详解
Nov 15 Python
用 Python 定义 Schema 并生成 Parquet 文件详情
Sep 25 Python
Python 的演示平台支持 WSGI 接口的应用
Apr 20 Python
使用python os模块复制文件到指定文件夹的方法
Aug 22 #Python
详解Django-channels 实现WebSocket实例
Aug 22 #Python
解决python3 requests headers参数不能有中文的问题
Aug 21 #Python
python通过robert、sobel、Laplace算子实现图像边缘提取详解
Aug 21 #Python
Python爬虫:url中带字典列表参数的编码转换方法
Aug 21 #Python
Python GUI学习之登录系统界面篇
Aug 21 #Python
Python爬虫:将headers请求头字符串转为字典的方法
Aug 21 #Python
You might like
php strtotime 函数UNIX时间戳
2009/01/14 PHP
php流量统计功能的实现代码
2012/09/29 PHP
thinkphp连贯操作实例分析
2014/11/22 PHP
Gambit vs CL BO3 第一场 2.13
2021/03/10 DOTA
AutoSave/自动存储功能实现
2007/03/24 Javascript
jquery等宽输出文字插件使用介绍
2013/09/18 Javascript
Jquery解析Json格式数据过程代码
2014/10/17 Javascript
JavaScript 里的类数组对象
2015/04/08 Javascript
JavaScript cookie详解及简单实例应用
2016/12/31 Javascript
javascript深拷贝和浅拷贝详解
2017/02/14 Javascript
jQuery实现文章图片弹出放大效果
2017/04/06 jQuery
jQuery获取table表中的td标签(实例讲解)
2017/07/28 jQuery
node中间层实现文件上传功能
2018/06/11 Javascript
解决select2在bootstrap modal中不能正常使用的问题
2018/08/09 Javascript
Vue根据条件添加click事件的方式
2019/11/09 Javascript
Vue通过for循环随机生成不同的颜色或随机数的实例
2019/11/09 Javascript
[01:03:18]DOTA2-DPC中国联赛 正赛 RNG vs Dynasty BO3 第一场 1月29日
2021/03/11 DOTA
Python脚本判断 Linux 是否运行在虚拟机上
2015/04/25 Python
Python下的Softmax回归函数的实现方法(推荐)
2017/01/26 Python
Python2与python3中 for 循环语句基础与实例分析
2017/11/20 Python
python常用函数与用法示例
2019/07/02 Python
python爬虫的一个常见简单js反爬详解
2019/07/09 Python
Pytorch加载部分预训练模型的参数实例
2019/08/18 Python
python中常见错误及解决方法
2020/06/21 Python
python字典与json转换的方法总结
2020/12/28 Python
详解如何用HTML5 Canvas API控制图片的缩放变换
2016/03/22 HTML / CSS
Sneaker Studio法国:购买运动鞋
2018/06/08 全球购物
Brasty罗马尼亚:购买手表、香水、化妆品、珠宝
2020/04/21 全球购物
电厂厂长岗位职责
2014/01/02 职场文书
《狮子和兔子》教学反思
2014/03/02 职场文书
励志演讲稿500字
2014/08/21 职场文书
班子四风对照检查材料
2014/08/21 职场文书
单位未婚证明范本
2014/11/25 职场文书
打架检讨书
2015/01/27 职场文书
2015年物流客服工作总结
2015/07/27 职场文书
Oracle锁表解决方法的详细记录
2022/06/05 Oracle