第十二课:QSsh 库编译及客户端开发

功能描述:QSsh 库编译以及如何运用 QSsh 做应用开发

一、最终演示效果

本次制作的 Demo 是通过输入主机的 IP 、端口号、用户名和密码,能够实现 SSH 自动连接,从而对远程设备进行操作。

主机(H):输入远程设备的 IP

端口(P):默认端口 22

用户名(U):输入远程设备的普通用户,系统默认禁止 root 用户 SSH,可以通过修改配置文件使得root 用户登录,建议还是使用普通用户登录

密码(W):用户名对应的登录密码

小圆圈图标表示 SSH 的状态,蓝色代表连接,红色代表断开

快速连接/断开:点击“快速连接”,如果 SSH 连接成功,则小圆圈图标变成蓝色,主机、端口号、用户名、用户名、密码的输入框失能,不允许输入,指令输入框使能,可输入指令,“快速连接”按钮文字变成“断开”,如果连接失败,则保持状态不变;点迹“断开”,如果 SSH 断开成功,则小圆圈图标变成红色,端口号、用户名、用户名、密码的输入框使能,允许输入,指令输入框失能,不允许输入指令,“断开”按钮文字变成“快速连接”,如果断开失败,则保持状态不变

指令输入框:输入 linux 指令,按回车键执行该指令

清空:点击“清空”按钮,轻触信息输出框的全部内容

文本输出框:显示 SSH 登录输出信息、指令执行信息等内容

二、QSsh 库编译过程

QSsh 为 Qt 提供 SSH 和 SFTP 支持,使你能方便快捷地使用 SSH 和 SFTP,但 QSsh 不是随 Qt 安装包一同安装的,需要自行编译。

编译过程如下:

1.下载 QSsh 源码包
https://download.csdn.net/download/tanou3212/88220985icon-default.png?t=N7T8https://download.csdn.net/download/tanou3212/88220985

2. 解压缩软件安装包,使用 QtCreator 打开 qssh.pro 文件,我使用的是 Qt 5.10.0 版本和 MinGW 编译器进行源码编译,其它版本的 Qt 和编译器设置类似

 3. 在 Debug 构建下,先点击“执行 qmake”,再“构建”

 4. 切换到 Release 构建下,再次点击“执行 qmake”,再“构建”

5. 经过第 3 步和第 4 步后, 在源码包下生成了一个 lib 文件夹,里面包含了libQSsh.a、QSsh.dll、libQSshd.a 和 QSshd.dll 四个文件,说明你已成功编译出 QSsh 的动态库了

三、运用 QSsh 做应用开发

1. QSsh 库的运用方法

将源码包主文件夹下的 “include” 的文件夹和 “lib” 文件夹拷贝到你的 Qt 工程目录下,然后在 .pro 文件中将 QSsh 的头文件路径和库文件路径添加到 INCLUDEPATH 和 LIBS 变量中

INCLUDEPATH = $$PWD/QSsh/include/ssh

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/QSsh/lib -lQSsh
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/QSsh/lib -lQSshd

2. QSsh 的应用开发

本次应用开发的目标如上图的演示效果,主要包含了 Ssh.cpp、Ssh.h、widget.h 和 widget.cpp 这四个文件,其中:

Ssh.h/Ssh.cpp:封装了 SSH 相关处理函数,供用户调用

widget.h/widget.cpp:整个界面的制作,并调用 Ssh 类中的处理函数

.pro 文件代码如下:

QT       += core gui network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = QSshDemo

TEMPLATE = app

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
        main.cpp \
        widget.cpp \
    Ssh.cpp

HEADERS += \
        widget.h \
    Ssh.h

INCLUDEPATH = $$PWD/QSsh/include/ssh

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/QSsh/lib -lQSsh
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/QSsh/lib -lQSshd

RESOURCES += \
    images.qrc

Ssh.h 文件代码如下:

#ifndef SSH_H
#define SSH_H

#include <sshconnection.h>
#include <sshremoteprocess.h>
#include <sftpchannel.h>
#include <QHostAddress>
#include <QThread>
#include <QTextCodec>

class Ssh : public QObject
{
    Q_OBJECT
public:
    /**
     * @brief Ssh
     * @param ip            IP 地址
     * @param port          端口号,默认 22
     * @param user          用户名
     * @param pwd           密码
     */
    explicit Ssh(QString ip, int port = 22, QString user = "yan",  QString pwd = "123123");

    /**
     * @brief init                              初始化 SSH,包括创建线程、创建 SSH 连接
     */
    void init();

    /**
     * @brief unInit                            退出线程
     */
    void unInit();

    /**
     * @brief isEnableSSH                       SSH 是否可用
     */
    bool isEnableSSH();

    /**
     *                                          释放内存
     */
    ~Ssh();

private:
    /**
     * @brief sendCmd                   向 SSH 写指令
     * @param message                   指令
     * @return                          写入成功的字节数
     */
    int sendCmd(QString message);

    /**
     * @brief getIpPort                 获取 IP 和 Port 的值
     * @return
     */
    QString getIpPort() {return strIp + ":" + QString::number(nPort);}

    /**
     * @brief convertCodeC              统一编码,防止中文乱码
     * @param ba
     * @return
     */
    QString convertCodeC(const QByteArray &ba);

    // 新建线程,用于 SSH
    QThread * thread = nullptr;
    // SSH 是否已连接
    bool bConnected = false;
    // SSH 是否可发送
    bool bSendable = false;

    // IP 地址
    QString strIp;
    // 端口号
    int nPort;
    // 用户名
    QString strUser;
    // 密码
    QString strPwd;

    // SSH 连接参数
    QSsh::SshConnectionParameters argParameters;
    // SSH Socket
    QSsh::SshConnection * sshSocket = nullptr;
    // Shell 脚本
    QSharedPointer<QSsh::SshRemoteProcess> shell;

signals:
    /**
     * @brief sigInit                   子线程和主线程交互
     */
    void sigInit();

    /**
     * @brief sigConnectStateChanged    SSH 连接状态改变
     * @param state                     true: 连接,  false: 断开
     * @param ip                        IP 地址
     * @param port                      端口号
     */
    void sigConnectStateChanged(bool state, QString ip, int port);

    /**
     * @brief sigDataArrived            SSH 接收数据再往外转发
     * @param msg                       数据
     * @param ip                        IP 地址
     * @param port                      端口号
     */
    void sigDataArrived(QString msg, QString ip, int port);

public slots:
    /**
     * @brief sigInitSlot
     */
    void sigInitSlot();

    /**
     * @brief resetConnection           重置 SSH 连接,即断开连接
     * @param ipPort                    IP 和端口,IP:端口
     */
    void resetConnection(QString ipPort);

    /**
     * @brief send                      向 SSH 写指令
     * @param message                   指令
     */
    void send(QString message);

    /**
     * @brief sendByQByteArray          向 SSH 写指令
     * @param ipPort                    IP:端口号
     * @param arrMsg                    指令
     */
    void sendByQByteArray(QString ipPort, QByteArray arrMsg);

    /**
     * @brief sshDisconnected           断开连接
     */
    void sshDisconnected();

    /**
     * @brief dataReceived              处理交互信息
     */
    void dataReceived();


private slots:
    /**
     * @brief createConnection          创建 SSH 连接
     */
    void createConnection();

    /**
     * @brief sshConnected              连接后处理,包括创建shell
     */
    void sshConnected();

    /**
     * @brief threadFinished            删除线程,释放内存
     */
    void threadFinished();

    /**
     * @brief sshConnectError           错误信息处理
     * @param sshError                  错误信息
     */
    void sshConnectError(QSsh::SshError sshError);

    /**
     * @brief shellStart                shell 开始
     */
    void shellStart();

    /**
     * @brief shellError                shell 发生错误
     */
    void shellError();
};

#endif // SSH_H

Ssh.cpp 文件代码如下: 

#include "ssh.h"
#include <QDebug>

Ssh::Ssh(QString ip, int port, QString user, QString pwd)
{
    strIp = ip;
    nPort = port;
    strUser = user;
    strPwd = pwd;
}

// 初始化 SSH,包括创建线程、创建 SSH 连接
void Ssh::init()
{
    thread = new QThread();
    connect(thread, SIGNAL(finished()), this, SLOT(threadFinished()));
    this->moveToThread(thread);
    thread->start();

    connect(this, SIGNAL(sigInit()), this, SLOT(sigInitSlot()));
    emit sigInit();
}

// 退出线程
void Ssh::unInit()
{
    thread->quit();
}

// SSH 是否可用
bool Ssh::isEnableSSH()
{
    if(bConnected && bSendable)
        return true;
    else
        return false;
}

Ssh::~Ssh()
{
    if(sshSocket)
    {
        delete sshSocket;
        sshSocket = nullptr;
    }
}

// 向 SSH 写指令
int Ssh::sendCmd(QString message)
{
    int nSize = 0;
    if(bConnected && bSendable)
    {
        nSize = shell->write(message.toUtf8().data());
    }
    else
    {
        qDebug() << "SSH 未连接或 shell 未连接:" << getIpPort();
    }

    return nSize;
}

// 统一编码,防止中文乱码
QString Ssh::convertCodeC(const QByteArray &ba)
{
    QTextCodec::ConverterState state;
    QString text = QTextCodec::codecForName("UTF-8")->toUnicode(ba.constData(), ba.size(), &state);
    if(state.invalidChars>0)
        text = QTextCodec::codecForName("GBK")->toUnicode(ba);
    else
        text = ba;
    return text;
}

void Ssh::sigInitSlot()
{
    argParameters.host = strIp;
    argParameters.port = nPort;
    argParameters.userName = strUser;
    argParameters.password = strPwd;
    argParameters.timeout = 10;
    // 密码方式连接
    argParameters.authenticationType = QSsh::SshConnectionParameters::AuthenticationTypePassword;
    // 连接
    createConnection();
}

// 重置 SSH 连接,即断开连接
void Ssh::resetConnection(QString ipPort)
{
    if(this->getIpPort() == ipPort)
    {
        this->sshDisconnected();
    }
}

// 向 SSH 写指令
void Ssh::send(QString message)
{
    sendCmd(message);
}

// 向 SSH 写指令
void Ssh::sendByQByteArray(QString ipPort, QByteArray arrMsg)
{
    if(ipPort.compare(getIpPort()))
        return;

    if(bConnected && bSendable)
        shell->write(arrMsg);
    else
        qDebug() << "发送失败,未建立连接:" << getIpPort();
}

// 断开连接
void Ssh::sshDisconnected()
{
    sshSocket->disconnectFromHost();
    // 此处断开需要时间,因此直接赋值false
    emit sigConnectStateChanged(false, strIp, nPort);
}

// 处理交互信息
void Ssh::dataReceived()
{
    QByteArray byteRecv = shell->readAllStandardOutput();
    QString strRecv = convertCodeC(byteRecv);

    if(strRecv.contains("password") || strRecv.contains(QString::fromLocal8Bit("密码")))
    {
        QString pwd = strPwd+"\n";
        shell->write(pwd.toUtf8().data());
    }

    if(strRecv.contains("yes/no/[fingerprint]"))
    {
        QString str = "yes\n";
        shell->write(str.toUtf8().data());
    }

    if(!strRecv.isEmpty()) //过滤空行
    {
        emit sigDataArrived(strRecv, strIp, nPort);
    }
}

// 创建 SSH 连接
void Ssh::createConnection()
{
    if(bConnected)
        return;

    if(!sshSocket)
    {
        sshSocket = new QSsh::SshConnection(argParameters);
        connect(sshSocket, SIGNAL(connected()), SLOT(sshConnected()));
        connect(sshSocket, SIGNAL(error(QSsh::SshError)), SLOT(sshConnectError(QSsh::SshError)));
    }
    sshSocket->connectToHost();
}

// 连接后处理,包括创建shell
void Ssh::sshConnected()
{
    shell = sshSocket->createRemoteShell();
    connect(shell.data(), SIGNAL(started()), SLOT(shellStart()));
    connect(shell.data(), SIGNAL(readyReadStandardOutput()), SLOT(dataReceived()));
    connect(shell.data(), SIGNAL(readyReadStandardError()), SLOT(shellError()));
    shell.data()->start();

    bConnected = true;
    emit sigConnectStateChanged(bConnected, strIp, nPort);
}

void Ssh::threadFinished()
{
    thread->deleteLater();
    this->deleteLater();
}

// 错误信息处理
void Ssh::sshConnectError(QSsh::SshError sshError)
{
    bSendable = false;
    bConnected = false;
    emit sigConnectStateChanged(bConnected, strIp, nPort);

    switch(sshError)
    {
    case QSsh::SshNoError:
        qDebug() << "sshConnectError SshNoError" << getIpPort();
        break;
    case QSsh::SshSocketError:
        qDebug() << "sshConnectError SshSocketError" << getIpPort();     // 拔掉网线是这种错误
        break;
    case QSsh::SshTimeoutError:
        qDebug() << "sshConnectError SshTimeoutError" << getIpPort();
        break;
    case QSsh::SshProtocolError:
        qDebug() << "sshConnectError SshProtocolError" << getIpPort();
        break;
    case QSsh::SshHostKeyError:
        qDebug() << "sshConnectError SshHostKeyError" << getIpPort();
        break;
    case QSsh::SshKeyFileError:
        qDebug() << "sshConnectError SshKeyFileError" << getIpPort();
        break;
    case QSsh::SshAuthenticationError:
        qDebug() << "sshConnectError SshAuthenticationError" << getIpPort();
        break;
    case QSsh::SshClosedByServerError:
        qDebug() << "sshConnectError SshClosedByServerError" << getIpPort();
        break;
    case QSsh::SshInternalError:
        qDebug() << "sshConnectError SshInternalError"<<getIpPort();
        break;
    default:
        break;
    }
}

// shell 开始
void Ssh::shellStart()
{
    bSendable = true;
    qDebug() << "shellStart Shell 已连接:" << getIpPort();
}

// shell 发生错误
void Ssh::shellError()
{
    qDebug() << "shellError Shell 发生错误:" << getIpPort();
}

widget.h 文件代码如下:  

#ifndef WIDGET_H
#define WIDGET_H

#include <QFrame>
#include <QFont>
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QRegExp>
#include <QRegExpValidator>
#include <QTextBrowser>
#include <QMessageBox>

#include "Ssh.h"

class Widget : public QFrame
{
    Q_OBJECT
public:
    Widget();

signals:
    /**
     * @brief sigSend   发送指令
     * @param cmd       指令
     */
    void sigSend(QString cmd);

    /**
     * @brief sigDisconnected  断开 SSH 连接
     */
    void sigDisconnected();

public slots:
    /**
     * @brief connectStateChanged           SSH 连接状态改变
     * @param state                         true: 连接,  false: 断开
     * @param ip                            IP 地址
     * @param port                          端口号
     */
    void connectStateChanged(bool state, QString ip, int port);

    /**
     * @brief dataArrived                   执行指令输出
     * @param msg                           信息
     * @param ip                            IP 地址
     * @param port                          端口号
     */
    void dataArrived(QString msg, QString ip, int port);

    /**
     * @brief sshConnect                    快速连接/断开
     */
    void sshConnect();

    /**
     * @brief executeCmd                    执行指令
     */
    void executeCmd();

    void clearText();
private:
    // 初始化界面
    void initUI();
    // 创建 ssh
    Ssh * ssh;
    // 字体
    QFont font;
    // 主机
    QLabel * hostLabel;
    QLineEdit * hostLineEdit;
    // 端口
    QLabel * portLabel;
    QLineEdit * portLineEdit;
    // 用户名
    QLabel * userNameLabel;
    QLineEdit * userNameLineEdit;
    // 密码
    QLabel * passwdLabel;
    QLineEdit * passwdLineEdit;
    // 连接状态
    QLabel * linkStateLabel;
    // 快速连接
    QPushButton * linkBtn;
    // 指令
    QLabel * cmdLabel;
    // 指令
    QLineEdit * cmdLineEdit;
    //清空
    QPushButton * clearBtn;
    // 输出信息
    QTextBrowser * textBrowser;
};

#endif // WIDGET_H

widget.cpp 文件代码如下: 

#include "widget.h"

Widget::Widget()
{
    setStyleSheet("background-color:#2B2C2E;color:rgba(255,255,255,0.85);");
    setFixedHeight(400);
    resize(700,400);
    initUI();
}

void Widget::connectStateChanged(bool state, QString ip, int port)
{
    Q_UNUSED(ip);
    Q_UNUSED(port);
    if(state)
    {
        linkStateLabel->setStyleSheet("background-color:transparent;"
                                      "background-image: url(:/Images/normalIcon.png);"
                                      "background-repeat: no-repeat;"
                                      "background-position: center center;");
        cmdLineEdit->setEnabled(true);

        linkBtn->setText("断开");
        linkStateLabel->setStyleSheet("background-image: url(:/Images/normalIcon.png);"
                                      "background-repeat: no-repeat;"
                                      "background-position: center center;");
        hostLineEdit->setDisabled(true);
        portLineEdit->setDisabled(true);
        userNameLineEdit->setDisabled(true);
        passwdLineEdit->setDisabled(true);

    }
    else
    {
        linkStateLabel->setStyleSheet("background-color:transparent;"
                                      "background-image: url(:/Images/breakIcon.png);"
                                      "background-repeat: no-repeat;"
                                      "background-position: center center;");
        cmdLineEdit->setDisabled(true);

        linkBtn->setText("快速连接");
        linkStateLabel->setStyleSheet("background-image: url(:/Images/breakIcon.png);"
                                      "background-repeat: no-repeat;"
                                      "background-position: center center;");
        hostLineEdit->setEnabled(true);
        portLineEdit->setEnabled(true);
        userNameLineEdit->setEnabled(true);
        passwdLineEdit->setEnabled(true);
    }
}

void Widget::dataArrived(QString msg, QString ip, int port)
{
    Q_UNUSED(ip);
    Q_UNUSED(port);
    textBrowser->append(msg);
}

void Widget::sshConnect()
{
    if(hostLineEdit->text().trimmed().isEmpty() || portLineEdit->text().trimmed().isEmpty() ||
            userNameLineEdit->text().trimmed().isEmpty() || passwdLineEdit->text().trimmed().isEmpty())
    {
        QMessageBox::warning(0,"警告","登录信息未填写完整");
        return;
    }

    if(linkBtn->text() == "快速连接")
    {
        ssh = new Ssh(hostLineEdit->text(), portLineEdit->text().toUInt(), userNameLineEdit->text(), passwdLineEdit->text());
        connect(ssh, SIGNAL(sigConnectStateChanged(bool,QString,int)), this, SLOT(connectStateChanged(bool,QString,int)));
        connect(ssh, SIGNAL(sigDataArrived(QString,QString,int)), this, SLOT(dataArrived(QString,QString,int)));
        connect(this, SIGNAL(sigSend(QString)), ssh, SLOT(send(QString)));
        connect(this, SIGNAL(sigDisconnected()), ssh, SLOT(sshDisconnected()));
        ssh->init();
    }
    else
    {
        emit sigDisconnected();
    }
}

void Widget::executeCmd()
{
    if(cmdLineEdit->text().trimmed().isEmpty())
        return;

    if(!ssh->isEnableSSH())
    {
        qDebug() << "SSH 不可用!";
        return;
    }

    QString cmd = cmdLineEdit->text().trimmed();
    // 如果是 ls 命令,去除文字颜色,否则显示一些无关的符号
    if((cmd.left(2) == "ls") || (cmd.left(2) == "ll"))
        cmd += " --color=none";
    cmd += " \r\n";
    emit sigSend(cmd);
    cmdLineEdit->clear();
}

void Widget::clearText()
{
    textBrowser->clear();
}

void Widget::initUI()
{
    font.setPixelSize(16);
    font.setFamily("黑体");

    hostLabel = new QLabel;
    hostLabel->setFont(font);
    hostLabel->setText("主机(H):");
    hostLabel->setFixedSize(90,32);
    hostLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight);

    hostLineEdit = new QLineEdit;
    font.setFamily("Times New Roman");
    hostLineEdit->setFixedSize(200,32);
    hostLineEdit->setFont(font);
    hostLineEdit->setAlignment(Qt::AlignCenter);
    hostLineEdit->setPlaceholderText("IP");
    hostLineEdit->setToolTip("请输入IP");
    QRegExp ipExp("((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)");
    QRegExpValidator * ipVal = new QRegExpValidator(ipExp);
    hostLineEdit->setValidator(ipVal);
    hostLineEdit->setStyleSheet("background-color:rgba(255,255,255,0.05); border-radius: 3px; margin:0px;");
    hostLineEdit->setText("192.168.1.100");

    font.setFamily("黑体");
    portLabel = new QLabel;
    portLabel->setFont(font);
    portLabel->setText("端口(P):");
    portLabel->setFixedSize(90,32);
    portLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight);

    portLineEdit = new QLineEdit;
    font.setFamily("Times New Roman");
    portLineEdit->setFixedSize(200,32);
    portLineEdit->setFont(font);
    portLineEdit->setAlignment(Qt::AlignCenter);
    portLineEdit->setPlaceholderText("端口号");
    portLineEdit->setToolTip("请输入端口号");
    QIntValidator * portVal = new QIntValidator(0,65535);
    portLineEdit->setValidator(portVal);
    portLineEdit->setStyleSheet("background-color:rgba(255,255,255,0.05); border-radius: 3px; margin:0px;");
    portLineEdit->setText("22");

    font.setFamily("黑体");
    userNameLabel = new QLabel;
    userNameLabel->setFont(font);
    userNameLabel->setText("用户名(U):");
    userNameLabel->setFixedSize(90,32);
    userNameLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight);
    userNameLabel->setStyleSheet("margin:0px;");

    userNameLineEdit = new QLineEdit;
    font.setFamily("Times New Roman");
    userNameLineEdit->setFixedSize(200,32);
    userNameLineEdit->setFont(font);
    userNameLineEdit->setAlignment(Qt::AlignCenter);
    userNameLineEdit->setPlaceholderText("用户名");
    userNameLineEdit->setToolTip("请输入用户名");
    QRegExp userNameExp("^[a-zA-Z0-9_][a-zA-Z0-9_]+$");
    QRegExpValidator * userNameVal = new QRegExpValidator(userNameExp);
    userNameLineEdit->setValidator(userNameVal);
    userNameLineEdit->setStyleSheet("background-color:rgba(255,255,255,0.05); border-radius: 3px; margin:0px;");
    userNameLineEdit->setText("yan");

    font.setFamily("黑体");
    passwdLabel = new QLabel;
    passwdLabel->setFont(font);
    passwdLabel->setText("密码(W):");
    passwdLabel->setFixedSize(90,32);
    passwdLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight);

    passwdLineEdit = new QLineEdit;
    font.setFamily("Times New Roman");
    passwdLineEdit->setFixedSize(200,32);
    passwdLineEdit->setFont(font);
    passwdLineEdit->setAlignment(Qt::AlignCenter);
    passwdLineEdit->setPlaceholderText("密码");
    passwdLineEdit->setEchoMode(QLineEdit::Password);
    passwdLineEdit->setToolTip("请输入密码");
    passwdLineEdit->setStyleSheet("background-color:rgba(255,255,255,0.05); border-radius: 3px;margin:0px;");
    passwdLineEdit->setText("123123");

    linkStateLabel = new QLabel;
    linkStateLabel->setFixedSize(90,32);
    linkStateLabel->setStyleSheet("background-image: url(:/Images/breakIcon.png);"
                                  "background-repeat: no-repeat;"
                                  "background-position: center center;");

    linkBtn = new QPushButton;
    font.setFamily("黑体");
    linkBtn->setFont(font);
    linkBtn->setText("快速连接");
    linkBtn->setStyleSheet("QPushButton{background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #5EDCF8, stop:0.5 #82E5FB, stop:1 #06C9F4); color:rgb(255,255,255); border-radius:8px; margin:0px;}"
                           "QPushButton:pressed{background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #c0c0c0, stop:1 #808080); color:rgb(255,255,255); border-radius:8px; margin:0px;}"
                           "QPushButton:disabled{background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #c0c0c0, stop:1 #808080); color:rgb(255,255,255); border-radius:8px; margin:0px;}");
    linkBtn->setFixedSize(112,32);
    connect(linkBtn, SIGNAL(clicked()), this, SLOT(sshConnect()));

    textBrowser = new QTextBrowser;
    font.setFamily("Times New Roman");
    textBrowser->setFont(font);
    textBrowser->setStyleSheet("background-color:rgba(255,255,255,0.05); border-radius: 3px;margin:0px;");

    cmdLabel = new QLabel;
    font.setFamily("黑体");
    cmdLabel->setFont(font);
    cmdLabel->setText("指令(回车执行):");
    cmdLabel->setFixedSize(140,32);
    cmdLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight);

    cmdLineEdit = new QLineEdit;
    font.setFamily("Times New Roman");
    cmdLineEdit->setFixedHeight(32);
    cmdLineEdit->setFont(font);
    cmdLineEdit->setAlignment(Qt::AlignCenter);
    cmdLineEdit->setPlaceholderText("指令");
    cmdLineEdit->setToolTip("请输入指令");
    cmdLineEdit->setStyleSheet("background-color:rgba(255,255,255,0.05); border-radius: 3px; margin:0px;");
    connect(cmdLineEdit, SIGNAL(returnPressed()), this, SLOT(executeCmd()));

    clearBtn = new QPushButton;
    font.setFamily("黑体");
    clearBtn->setFont(font);
    clearBtn->setText("清空");
    clearBtn->setStyleSheet("QPushButton{background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #5EDCF8, stop:0.5 #82E5FB, stop:1 #06C9F4); color:rgb(255,255,255); border-radius:8px; margin:0px;}"
                           "QPushButton:pressed{background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #c0c0c0, stop:1 #808080); color:rgb(255,255,255); border-radius:8px; margin:0px;}"
                           "QPushButton:disabled{background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #c0c0c0, stop:1 #808080); color:rgb(255,255,255); border-radius:8px; margin:0px;}");
    clearBtn->setFixedSize(60,32);
    connect(clearBtn, SIGNAL(clicked()), this, SLOT(clearText()));

    QHBoxLayout * hostLayout = new QHBoxLayout;
    hostLayout->setMargin(0);
    hostLayout->setContentsMargins(5,5,5,5);
    hostLayout->setSpacing(0);
    hostLayout->addWidget(hostLabel);
    hostLayout->addWidget(hostLineEdit);

    QHBoxLayout * portLayout = new QHBoxLayout;
    portLayout->setMargin(0);
    portLayout->setContentsMargins(5,5,5,5);
    portLayout->setSpacing(0);
    portLayout->addWidget(portLabel);
    portLayout->addWidget(portLineEdit);

    QHBoxLayout * userNameLayout = new QHBoxLayout;
    userNameLayout->setMargin(0);
    userNameLayout->setContentsMargins(5,5,5,5);
    userNameLayout->setSpacing(0);
    userNameLayout->addWidget(userNameLabel);
    userNameLayout->addWidget(userNameLineEdit);

    QHBoxLayout * passwdLayout = new QHBoxLayout;
    passwdLayout->setMargin(0);
    passwdLayout->setContentsMargins(5,5,5,5);
    passwdLayout->setSpacing(0);
    passwdLayout->addWidget(passwdLabel);
    passwdLayout->addWidget(passwdLineEdit);

    QHBoxLayout * linkLayout = new QHBoxLayout;
    linkLayout->setMargin(0);
    linkLayout->setContentsMargins(5,5,5,5);
    linkLayout->setSpacing(20);
    linkLayout->addWidget(linkStateLabel);
    linkLayout->addWidget(linkBtn,0,Qt::AlignVCenter|Qt::AlignRight);

    QHBoxLayout * cmdLayout = new QHBoxLayout;
    cmdLayout->setMargin(0);
    cmdLayout->setContentsMargins(5,5,5,5);
    cmdLayout->setSpacing(0);
    cmdLayout->addWidget(cmdLabel);
    cmdLayout->addWidget(cmdLineEdit);
    cmdLayout->addSpacing(10);
    cmdLayout->addWidget(clearBtn);

    QVBoxLayout * leftLayout = new QVBoxLayout;
    leftLayout->setMargin(0);
    leftLayout->setContentsMargins(0,0,0,0);
    leftLayout->setSpacing(0);
    leftLayout->addLayout(hostLayout);
    leftLayout->addStretch(1);
    leftLayout->addLayout(portLayout);
    leftLayout->addStretch(1);
    leftLayout->addLayout(userNameLayout);
    leftLayout->addStretch(1);
    leftLayout->addLayout(passwdLayout);
    leftLayout->addStretch(1);
    leftLayout->addLayout(linkLayout);

    QHBoxLayout * topLayout = new QHBoxLayout;
    topLayout->setMargin(0);
    topLayout->setContentsMargins(0,0,0,0);
    topLayout->setSpacing(20);
    topLayout->addLayout(leftLayout);
    topLayout->addWidget(textBrowser);

    QVBoxLayout * mainLayout = new QVBoxLayout;
    mainLayout->setMargin(0);
    mainLayout->setContentsMargins(24,24,24,24);
    mainLayout->setSpacing(10);
    mainLayout->addLayout(topLayout,0);
    mainLayout->addLayout(cmdLayout);
    setLayout(mainLayout);
}

完整的代码已经贴上,每个函数的备注写的非常清楚,如有不清楚的地方可以私信我。

四、为 root 用户开启 SSH 登录

Linux 默认不允许以 root 用户进行 SSH 登录,如需以 root 用户 SSH,需按照以下配置为 root 用户开启 SSH 登录权限

第 1 步:在远程设备(即 SSH 登录的设备)上,以 root 权限编辑 /etc/ssh/sshd_config 文件

#sudo gedit /etc/ssh/sshd_config

第 2 步:找到 PermitRootLogin prohibit-password 或者 PermitRootLogin without-password,用 “#” 注释掉这行,在其后添加一行 PermitRootLogin yes

#PermitRootLogin prohibit-password
PermitRootLogin yes

 第 3 步:重启ssh服务

sudo service ssh restart

现在 root 用户可以登录 SSH 了

写在最后的话

如果出现中文乱码的问题,请参考我的另外一篇博客《第十课:Qt 字符编码和中文乱码相关问题》 ,百分百能解决你的问题!

如果你没有积分或者不是会员,请联系我,私发你压缩包!

  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 22
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yann@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值