qt process类进行ssh远程控制

在qt5.12.6中想使用QProcess类进行ssh连接,显示总是连接成功返回值为空,这个为什么?怎么解决?或者说应该怎么写?(已经在终端和用putty测试了ssh可以正常连接而且打印正常,都是root/)
编译输出结果如下:

[Krn64.dll][25024][25844][INFO] [ProcessInject::HookCreateProcessW] [NULL], [ssh  root@192.168.234.100] is not cmd process, no need remote inject
QProcess::start: Process is already running
QProcess: Destroyed while process ("ssh") is still running.
Exit code: 62097
Exit status: QProcess::CrashExit
Output: ""
Error: ""
Process crashed. Error:  "Process crashed"
subWidgetSwitched QMdiSubWindow(0x5be2600)

img


    // 创建一个QProcess对象
    QProcess process;

    QStringList command;
    process.setProcessChannelMode(QProcess::SeparateChannels);
  command  << "root@192.168.234.100" <<"pwd";
    process.start("ssh", command);

if (process.waitForStarted())
{
    process.closeWriteChannel();

    QObject::connect(&process, &QProcess::readyReadStandardOutput, [&](){
        qDebug() << "Output: " << process.readAllStandardOutput();
    });

    QObject::connect(&process, &QProcess::readyReadStandardError, [&](){
        qDebug() << "Error: " << process.readAllStandardError();
    });

    // 异步等待命令执行完成
    QObject::connect(&process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [&](int exitCode, QProcess::ExitStatus exitStatus){
        QByteArray result = process.readAllStandardOutput();
        QByteArray error = process.readAllStandardError();

        qDebug() << "Exit code:" << exitCode;
        qDebug() << "Exit status:" << exitStatus;
        qDebug() << "Output:" << result;
        qDebug() << "Error:" << error;
             if (exitStatus == QProcess::CrashExit) {
                qDebug() << "Process crashed. Error: " << process.errorString();
            }
    });
}
else
{
    qDebug() << "Failed to start the command.";
}

ssh参数给的有问题,不能这么给用户名和密码,所以链接错误。


#include <QProcess>

int main(int argc, char *argv[])
{
    QProcess process;

    process.start("ssh", QStringList() << "root@192.168.234.100" << "pwd");

    if (process.waitForStarted()) {
        process.closeWriteChannel();

        QObject::connect(&process, &QProcess::readyReadStandardOutput, [this] {
            qDebug() << "Output: " << process.readAllStandardOutput();
        });

        QObject::connect(&process, &QProcess::readyReadStandardError, [this] {
            qDebug() << "Error: " << process.readAllStandardError();
        });

        QObject::connect(&process, &QProcess::finished, [this, exitCode] {
            if (exitCode == QProcess::CrashExit) {
                qDebug() << "Process crashed. Error: " << process.errorString();
            }
            emit finished(exitCode);
        });
    } else {
        qDebug() << "Failed to start the command.";
    }

    return 0;
}

参考
(1) Building Qt 5 from Git https://wiki.qt.io/Building_Qt_5_from_Git
(2) QProcess Class | Qt Core 6.5.1. https://doc.qt.io/qt-6/qprocess.html
(3) Qt QSsh 使用 windows Qt实现ssh客户端 https://blog.csdn.net/qq_41673920/article/details/103687644

Qt_QSsh 使用 windows Qt实现ssh客户端
CConnectionForSshClient.h

#ifndef CCONNECTIONFORSSHCLIENT_H
#define CCONNECTIONFORSSHCLIENT_H
 
/* Func:以用户密码的形式连接ssh服务器  发送命令到shell执行  需加\n
 * Note:定时检查连接状态的逻辑是  连接成功关闭定时器检查
 *      连接断开  开启定时器检查并尝试重连  直至连接成功
 *      即关闭定时器检查
 * Use:绑定两个信号
 *      检测状态:sigConnectStateChanged(bState,strIp,nPort);
 *      接收信息:sigDataArrived(QString strMsg,QString strIp, int nPort);
 *     绑定一个槽
 *      发送信息:void slotSend(QString strMsg);
 */
#include <sshconnection.h>
#include <sshremoteprocess.h>
#include <sftpchannel.h>
#include <QTimer>
#include <QHostAddress>
#include <QThread>
 
 
#define RECONNET_SPAN_TIME (1000*10)  //连接状态心跳
 
 
class  CConnectionForSshClient : public QObject
{
    Q_OBJECT
public:
    explicit CConnectionForSshClient(QString strIp, int nPort = 22,QString strPwd = "17909",QString strUser = "root");
 
    void init();
    void unInit();
 
    ~CConnectionForSshClient();
private:
    QThread *m_pThread = nullptr;
    bool m_bConnected = false;
    bool m_bIsFirstConnect = true;
    bool m_bSendAble = false;
 
    QTimer *m_pTimer;
 
    QString m_strIp = "";
    int m_nPort = -1;
    QString m_strUser;
    QString m_strPwd;
    QString m_strIpPort;
 
    QSsh::SshConnectionParameters m_argParameters;
    QSsh::SshConnection *m_pSshSocket = nullptr;
    QSharedPointer<QSsh::SshRemoteProcess> m_shell;
signals:
    void sigInitForClild();
    void sigConnectStateChanged(bool bState,QString strIp,int nPort);
    void sigDataArrived(QString strMsg,QString strIp, int nPort);
private:
    int send(QString strMessage);
    QString getIpPort(){return m_strIp + ":" + QString::number(m_nPort);}
public slots:
    void slotResetConnection(QString strIpPort);
    void slotSend(QString strIpPort,QString strMessage);
    void slotSend(QString strMsg);
    void slotSendByQByteArray(QString strIpPort,QByteArray arrMsg);
    void slotDisconnected();
    void slotDataReceived();
private slots:
    void slotInitForClild();
    void slotCreateConnection();
    void slotConnected();
 
    void slotThreadFinished();
 
    void slotSshConnectError(QSsh::SshError sshError);
    void slotShellStart();
    void slotShellError();
};
 
#endif // CCONNECTIONFORSSHCLIENT_H
 

CConnectionForSshClient.cpp

#include "CConnectionForSshClient.h"
#include <QDebug>
 
 
CConnectionForSshClient::CConnectionForSshClient(QString strIp, int nPort, QString strPwd, QString strUser)
{
    m_strIp = strIp;
    m_nPort = nPort;
    m_strUser = strUser;
    m_strPwd = strPwd;
    m_strIpPort = m_strIp + ":" + QString::number(m_nPort);
}
 
void CConnectionForSshClient::init()
{
    m_pThread = new QThread();
    connect(m_pThread,SIGNAL(finished()),this,SLOT(slotThreadFinished()));
    this->moveToThread(m_pThread);
    m_pThread->start();
 
    //之后的逻辑都得通过信号和槽接通
    connect(this,SIGNAL(sigInitForClild()),this,SLOT(slotInitForClild()));
    emit sigInitForClild();
}
 
void CConnectionForSshClient::unInit()
{
    m_pThread->quit();
}
 
int CConnectionForSshClient::send(QString strMessage)
{
    qDebug()<<"CConnectionForSshClient ssh send "<<strMessage;
 
    int nSize = 0;
    if(m_bConnected && m_bSendAble){
       nSize = m_shell->write(strMessage.toLatin1().data());
    }else{
       qDebug()<<"CConnectionForSshClient::send() ssh未连接 或 shell未连接:"<<getIpPort();
    }
 
    return nSize;
}
 
CConnectionForSshClient::~CConnectionForSshClient()
{
    if(nullptr != m_pSshSocket){
        delete m_pSshSocket;
        m_pSshSocket = nullptr;
    }
}
 
void CConnectionForSshClient::slotResetConnection(QString strIpPort)
{
    if(this->getIpPort() == strIpPort){
        this->slotDisconnected();
    }
}
 
void CConnectionForSshClient::slotSend(QString strIpPort, QString strMessage)
{
    if(0 != m_strIpPort.compare(strIpPort)){
        return;
    }
 
    send(strMessage);
}
 
void CConnectionForSshClient::slotSendByQByteArray(QString strIpPort, QByteArray arrMsg)
{
    if(0 != m_strIpPort.compare(strIpPort)){
        return;
    }
 
    if(m_bConnected){
       m_shell->write(arrMsg);
    }else{
       qDebug()<<"CConnectionForSshClient::send(QString strMessage) 发送失败 未建立连接:"<<getIpPort();
    }
}
 
void CConnectionForSshClient::slotInitForClild()
{
    m_argParameters.port = m_nPort;
    m_argParameters.userName = m_strUser;
    m_argParameters.password = m_strPwd;
    m_argParameters.host = m_strIp;
    m_argParameters.timeout = 10;
    m_argParameters.authenticationType =
            QSsh::SshConnectionParameters::AuthenticationTypePassword; //密码方式连接
 
    slotCreateConnection(); //连接
 
    m_pTimer = new QTimer(this);
    m_pTimer->setInterval(RECONNET_SPAN_TIME);
    connect(m_pTimer,SIGNAL(timeout()),this,SLOT(slotCreateConnection()));
    m_pTimer->start();//启动心跳定时器,每隔一段时间进入slotCreateConnection判断是否需要重连
}
 
void CConnectionForSshClient::slotCreateConnection()
{
 
    qDebug()<<"CConnectionForSshClient::slotCreateConnection检查连接" ;
 
    if(true == m_bConnected)
        return;
 
    if(nullptr == m_pSshSocket){
        m_pSshSocket = new QSsh::SshConnection(m_argParameters);
        connect(m_pSshSocket,SIGNAL(connected()),SLOT(slotConnected()));
        connect(m_pSshSocket,SIGNAL(error(QSsh::SshError)),SLOT(slotSshConnectError(QSsh::SshError)));
    }
    m_pSshSocket->connectToHost();
    qDebug()<<"CConnectionForSshClient::slotCreateConnection() 以ssh方式 尝试连接:"<<getIpPort();
}
 
void CConnectionForSshClient::slotConnected()
{
    qDebug()<<"CConnectionForSshClient::slotConnected ssh已连接到:"<<getIpPort();
    m_pTimer->stop();
 
    m_shell = m_pSshSocket->createRemoteShell();
    connect(m_shell.data(), SIGNAL(started()), SLOT(slotShellStart()));
    connect(m_shell.data(), SIGNAL(readyReadStandardOutput()), SLOT(slotDataReceived()));
    connect(m_shell.data(), SIGNAL(readyReadStandardError()), SLOT(slotShellError()));
    m_shell.data()->start();
 
    m_bConnected = true;
    emit sigConnectStateChanged(m_bConnected,m_strIp,m_nPort);
}
 
void CConnectionForSshClient::slotDisconnected()
{
    m_pSshSocket->disconnectFromHost();
}
 
void CConnectionForSshClient::slotThreadFinished()
{
    m_pThread->deleteLater();
    this->deleteLater();
}
 
void CConnectionForSshClient::slotSshConnectError(QSsh::SshError sshError)
{
    m_bSendAble = false;
    m_bConnected = false;
    emit sigConnectStateChanged(m_bConnected,m_strIp,m_nPort);
 
    m_pTimer->start();
 
    switch(sshError){
    case QSsh::SshNoError:
        qDebug()<<"slotSshConnectError SshNoError"<<getIpPort();
        break;
    case QSsh::SshSocketError:
        qDebug()<<"slotSshConnectError SshSocketError"<<getIpPort(); //拔掉网线是这种错误
        break;
    case QSsh::SshTimeoutError:
        qDebug()<<"slotSshConnectError SshTimeoutError"<<getIpPort();
        break;
    case QSsh::SshProtocolError:
        qDebug()<<"slotSshConnectError SshProtocolError"<<getIpPort();
        break;
    case QSsh::SshHostKeyError:
        qDebug()<<"slotSshConnectError SshHostKeyError"<<getIpPort();
        break;
    case QSsh::SshKeyFileError:
        qDebug()<<"slotSshConnectError SshKeyFileError"<<getIpPort();
        break;
    case QSsh::SshAuthenticationError:
        qDebug()<<"slotSshConnectError SshAuthenticationError"<<getIpPort();
        break;
    case QSsh::SshClosedByServerError:
        qDebug()<<"slotSshConnectError SshClosedByServerError"<<getIpPort();
        break;
    case QSsh::SshInternalError:
        qDebug()<<"slotSshConnectError SshInternalError"<<getIpPort();
        break;
    default:
        break;
    }
 
}
 
void CConnectionForSshClient::slotShellStart()
{
    m_bSendAble = true;
    qDebug()<<"CConnectionForSshClient::slotShellStart Shell已连接:"<<getIpPort();
}
 
void CConnectionForSshClient::slotShellError()
{
    qDebug()<<"CConnectionForSshClient::slotShellError Shell发生错误:"<<getIpPort();
}
 
void CConnectionForSshClient::slotSend(QString strMessage)
{
    send(strMessage);
}
 
void CConnectionForSshClient::slotDataReceived()
{
    QByteArray byteRecv = m_shell->readAllStandardOutput();
    QString strRecv = QString::fromUtf8(byteRecv);
 
//    if(strRecv.contains("password for")){
//        m_shell->write(m_strPwd.toLatin1().data());
//    }
 
    if(!strRecv.isEmpty()) //过滤空行
        emit sigDataArrived(strRecv, m_strIp, m_nPort);
 
}
 

我觉得应该是你传递参数的问题,首先要确保在连接ssh时输入了正确的用户名密码等参数,才能连接到SSH。你现在看起是连接成功了,但是返回为空,有可能是还没有正确连接到所以才会出现为空的现象。
具体实现可以参考:
封装一个类,名称为CSSHPROCESS,类的作用为实现SSH与远程机器交互:https://qt.0voice.com/?id=32

传递参数格式不对吧

检查一下传参是否正确

根据你提供的代码,问题可能出在以下几个方面:

  1. SSH连接参数不正确:确认SSH连接的参数是否正确,包括SSH用户名、IP地址和端口号等。确保这些参数与你在终端或Putty中测试成功的参数一致。

  2. QProcess命令参数不正确:在你的代码中,你将目标IP地址作为命令参数传递给SSH命令。但是SSH命令需要指定SSH连接的目标主机,而不是直接的IP地址。正确的SSH命令应该是ssh root@192.168.234.100,而不仅仅是root@192.168.234.100。因此,你需要将SSH命令和目标主机作为两个参数传递给process.start()方法。

修改后的代码应该类似于:

QStringList command;
command << "ssh" << "root@192.168.234.100";
process.start("ssh", command);
  1. QProcess信号连接不正确:在你的代码中,你将QProcess::finished信号连接到一个lambda函数,并在该函数中读取输出和错误信息。然而,这些读取操作应该在QProcess::readyReadStandardOutputQProcess::readyReadStandardError信号的槽函数中完成。因此,你需要将输出和错误信息的读取操作移到对应的槽函数中。

修改后的代码应该类似于:

QObject::connect(&process, &QProcess::readyReadStandardOutput, [&]() {
    qDebug() << "Output: " << process.readAllStandardOutput();
});

QObject::connect(&process, &QProcess::readyReadStandardError, [&]() {
    qDebug() << "Error: " << process.readAllStandardError();
});

// 异步等待命令执行完成
QObject::connect(&process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [&](int exitCode, QProcess::ExitStatus exitStatus) {
    QByteArray result = process.readAllStandardOutput();
    QByteArray error = process.readAllStandardError();

    qDebug() << "Exit code:" << exitCode;
    qDebug() << "Exit status:" << exitStatus;
    qDebug() << "Output:" << result;
    qDebug() << "Error:" << error;
});

请注意,为了能够正确接收到输出和错误信息,建议将process.setProcessChannelMode(QProcess::SeparateChannels)设置放在process.start()之前。

希望这些修改能够解决你的问题!如果还有其他疑问,请随时提问。