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 18 Python
有关wxpython pyqt内存占用问题分析
Jun 09 Python
解决windows下Sublime Text 2 运行 PyQt 不显示的方法分享
Jun 18 Python
Python和GO语言实现的消息摘要算法示例
Mar 10 Python
Python爬虫实现网页信息抓取功能示例【URL与正则模块】
May 18 Python
python web.py开发httpserver解决跨域问题实例解析
Feb 12 Python
快速解决Django关闭Debug模式无法加载media图片与static静态文件
Apr 07 Python
python 一维二维插值实例
Apr 22 Python
Django通过json格式收集主机信息
May 29 Python
python GUI模拟实现计算器
Jun 22 Python
python如何进入交互模式
Jul 06 Python
详解python with 上下文管理器
Sep 02 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开发者事半功倍的十大技巧小结
2010/04/20 PHP
php中的PHP_EOL换行符详细解析
2013/10/26 PHP
Ubuntu中搭建Nginx、PHP环境最简单的方法
2015/03/05 PHP
php在数据库抽象层简单使用PDO的方法
2015/11/03 PHP
php结合md5实现的加密解密方法
2016/01/25 PHP
php+layui数据表格实现数据分页渲染代码
2019/10/26 PHP
PHP连接SQL server数据库测试脚本运行实例
2020/08/24 PHP
js获取单选按钮的数据
2006/11/27 Javascript
js刷新框架子页面的七种方法代码
2008/11/20 Javascript
Jquery 设置标题的自动翻转
2009/10/03 Javascript
javascript基础第一章 JavaScript与用户端
2010/07/22 Javascript
jQuery获取当前对象标签名称的方法
2014/02/07 Javascript
nodejs实现黑名单中间件设计
2014/06/17 NodeJs
javascript实现不同颜色Tab标签切换效果
2016/04/27 Javascript
微信小程序之仿微信漂流瓶实例
2016/12/09 Javascript
Bootstrap模态窗口源码解析
2017/02/08 Javascript
利用express启动一个server服务的方法
2017/09/17 Javascript
浅谈vue项目如何打包扔向服务器
2018/05/08 Javascript
详解基于electron制作一个node压缩图片的桌面应用
2019/01/29 Javascript
JS实现轮播图效果
2020/01/11 Javascript
CKEditor扩展插件:自动排版功能autoformat插件实现方法详解
2020/02/06 Javascript
Openlayers实现图形绘制
2020/09/28 Javascript
python基础知识小结之集合
2015/11/25 Python
python写入已存在的excel数据实例
2018/05/03 Python
python实现内存监控系统
2021/03/07 Python
Python filter过滤器原理及实例应用
2020/08/18 Python
HTML5 绘制图像(上)之:关于canvas元素引领下一代web页面的问题
2013/04/24 HTML / CSS
2015年幼儿园毕业感言
2014/02/12 职场文书
大型营销活动计划书
2014/04/28 职场文书
体育之星事迹材料
2014/05/11 职场文书
教师演讲稿大全
2014/05/16 职场文书
元旦趣味活动方案
2014/08/22 职场文书
董事长助理岗位职责
2015/02/11 职场文书
发票退票证明
2015/06/24 职场文书
MySQL中的布尔值,怎么存储false或true
2021/06/04 MySQL
win11电脑关机鼠标灯还亮怎么解决? win11关机后鼠标灯还亮解决方法
2023/01/09 数码科技