功能描述: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/88220985https://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);
}
完整的代码已经贴上,每个函数的备注写的非常清楚,如有不清楚的地方可以私信我。
完整代码压缩包下载地址:
https://download.csdn.net/download/tanou3212/88221081https://download.csdn.net/download/tanou3212/88221081
四、为 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 字符编码和中文乱码相关问题》 ,百分百能解决你的问题!
如果你没有积分或者不是会员,请联系我,私发你压缩包!