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 相关文章推荐
开源Web应用框架Django图文教程
Mar 09 Python
python+selenium开发环境搭建图文教程
Aug 11 Python
python中lambda()的用法
Nov 16 Python
Python批量发送post请求的实现代码
May 05 Python
Sanic框架安装与简单入门示例
Jul 16 Python
在pandas多重索引multiIndex中选定指定索引的行方法
Nov 16 Python
Python 普通最小二乘法(OLS)进行多项式拟合的方法
Dec 29 Python
wxPython实现列表增删改查功能
Nov 19 Python
python 读取数据库并绘图的实例
Dec 03 Python
Python之Class&Object用法详解
Dec 25 Python
Android Q之气泡弹窗的实现示例
Jun 23 Python
详解python内置模块urllib
Sep 09 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+JS无限级可伸缩菜单详解(简单易懂)
2007/01/02 PHP
php字符编码转换之gb2312转为utf8
2013/10/28 PHP
php查看一个变量的占用内存的实例代码
2020/03/29 PHP
用 javascript 实现的点击复制代码
2007/03/24 Javascript
window.location的重写及判断location是否被重写
2014/09/04 Javascript
jQuery实现的感应鼠标悬停图片色彩渐显效果
2015/03/03 Javascript
JS+CSS实现带小三角指引的滑动门效果
2015/09/22 Javascript
AngularJS入门教程之控制器详解
2016/07/27 Javascript
Bootstrap CDN和本地化环境搭建
2016/10/26 Javascript
Jquery根据浏览器窗口改变调整大小的方法
2017/02/07 Javascript
在vue中添加Echarts图表的基本使用教程
2017/11/22 Javascript
Angular5.1新功能分享
2017/12/21 Javascript
VUE 3D轮播图封装实现方法
2018/07/03 Javascript
vue.js2.0 实现better-scroll的滚动效果实例详解
2018/08/13 Javascript
微信小程序添加插屏广告并设置显示频率(一天一次)
2019/12/06 Javascript
解决在Vue中使用axios POST请求变成OPTIONS的问题
2020/08/14 Javascript
antd中table展开行默认展示,且不需要前边的加号操作
2020/11/02 Javascript
vue 使用localstorage实现面包屑的操作
2020/11/16 Javascript
Python正则表达式知识汇总
2017/09/22 Python
python买卖股票的最佳时机(基于贪心/蛮力算法)
2019/07/05 Python
Python实现某论坛自动签到功能
2019/08/20 Python
python实现信号时域统计特征提取代码
2020/02/26 Python
python GUI库图形界面开发之PyQt5表格控件QTableView详细使用方法与实例
2020/03/01 Python
jupyter notebook 恢复误删单元格或者历史代码的实现
2020/04/17 Python
TensorFlow Autodiff自动微分详解
2020/07/06 Python
python能做哪些生活有趣的事情
2020/09/09 Python
Skyscanner波兰:廉价航班
2017/11/07 全球购物
Tenstickers法国:墙贴和装饰贴纸
2019/08/26 全球购物
揠苗助长教学反思
2014/02/04 职场文书
成龙霸王洗发水广告词
2014/03/14 职场文书
爱我中华教学反思
2014/04/28 职场文书
2014年度思想工作总结
2014/11/27 职场文书
四群教育工作总结
2015/08/10 职场文书
500字作文之关于爸爸
2019/11/14 职场文书
python OpenCV学习笔记
2021/03/31 Python
将Python代码打包成.exe可执行文件的完整步骤
2021/05/12 Python