「Qtの基礎 - SSH」の版間の差分

ナビゲーションに移動 検索に移動
419行目: 419行目:


== libSSH2ライブラリを使用したコマンドの使用例 ==
== libSSH2ライブラリを使用したコマンドの使用例 ==
==== ブロッキングモード ====
以下の例では、リモート側のPCにSSH接続して、lsコマンドを実行してその結果をローカル側のPCに表示している。<br>
以下の例では、リモート側のPCにSSH接続して、lsコマンドを実行してその結果をローカル側のPCに表示している。<br>
<br>
<br>
以下の例は、<u>ブロッキングモード</u>でlsコマンドを実行している。<br>
以下の例は、<u>ブロッキングモード</u>でlsコマンドを実行している。<br>
もし、<u>ノンブロッキングモード</u> (シグナル / スロット) で設計する場合、libSSH2ライブラリの関数呼び出しは即座に返されて、処理がバックグラウンドで非同期に進行する。<br>
これにより、プログラムは他の処理を続行でき、必要に応じてリモートホストとの通信が完了するのを待つことができる。<br>
<br>
ノンブロッキングモードを使用する場合、特に入出力操作が発生する待ち時間を最小限に抑え、プログラムがより効率的に動作することが期待される。<br>
しかし、ノンブロッキングモードを扱う際には、非同期処理やイベント駆動型のプログラミングに慣れる必要がある。<br>
<br>
<br>
  <syntaxhighlight lang="make">
  <syntaxhighlight lang="make">
595行目: 591行目:
   
   
     // チャンネルの終了を確認
     // チャンネルの終了を確認
    // 終了コードおよび終了シグナルを取得して表示
     int  exitcode    = 127;
     int  exitcode    = 127;
     char *exitsignal = nullptr;
     char *exitsignal = nullptr;
630行目: 627行目:
   
   
  #endif // DIVIDEBYZEROEXCEPTION_H
  #endif // DIVIDEBYZEROEXCEPTION_H
</syntaxhighlight>
<br>
==== ノンブロッキングモード ====
以下の例では、リモート側のPCにSSH接続して、lsコマンドを実行してその結果をローカル側のPCに表示している。<br>
<br>
以下の例は、<u>ノンブロッキングモード</u>でlsコマンドを実行している。<br>
<u>ノンブロッキングモード</u> (シグナル / スロット) で設計する場合、libSSH2ライブラリの関数呼び出しは即座に返されて、処理がバックグラウンドで非同期に進行する。<br>
これにより、プログラムは他の処理を続行でき、必要に応じてリモートホストとの通信が完了するのを待つことができる。<br>
<br>
ノンブロッキングモードを使用する場合、特に入出力操作が発生する待ち時間を最小限に抑え、プログラムがより効率的に動作することが期待される。<br>
しかし、ノンブロッキングモードを扱う際には、非同期処理やイベント駆動型のプログラミングに慣れる必要がある。<br>
<br>
<syntaxhighlight lang="c++">
// SSHClient.hファイル
#include <QCoreApplication>
#include <QTcpSocket>
#include <QTimer>
#include <QDebug>
#include <libssh2.h>
class SSHClient : public QObject
{
    Q_OBJECT
private:
    QTcpSocket      *m_Socket;
    LIBSSH2_SESSION *m_Session;
    LIBSSH2_CHANNEL *m_Channel;
    QString        m_Host;
    quint16        m_Port;
    QString        m_User;
    QString        m_Passwaord;
public:
    SSHClient(QObject *parent = nullptr);
    ~SSHClient();
    void connectToHost();
private slots:
    void onConnected();
    void authenticateUser();
    void openChannel();
    void executeCommand();
    void onReadyRead();
    void readOutput();
    void closeChannel();
};
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// SSHClient.cppファイル
#include "SSHClient.h"
SSHClient::SSHClient(QObject *parent = nullptr) : QObject(parent), session(nullptr), channel(nullptr)
{
    m_Socket = new QTcpSocket(this);
    connect(m_Socket, &QTcpSocket::connected, this, &SSHClient::onConnected);
    connect(m_Socket, &QTcpSocket::readyRead, this, &SSHClient::onReadyRead);
    // libSSH2ライブラリの初期化
    if (libssh2_init(0) != 0) {
      qDebug() << "libSSH2ライブラリの初期化に失敗";
      return;
    }
}
SSHClient::~SSHClient()
{
    if (m_Channel) libssh2_channel_free(m_Channel);
    if (m_Session) {
      libssh2_session_disconnect(m_Session, "Normal Shutdown");
      libssh2_session_free(m_Session);
    }
    libssh2_exit();
}
void SSHClient::connectToHost()
{
    m_Socket->connectToHost(m_Host, m_Port);
}
void SSHClient::onConnected()
{
    qDebug() << "ホストへの接続に成功";
    m_Session = libssh2_session_init();
    libssh2_session_set_blocking(m_Session, 0);
    int rc = 0;
    do {
      rc = libssh2_session_handshake(m_Sssion, m_Socket->socketDescriptor());
    } while (rc == LIBSSH2_ERROR_EAGAIN);
    if (rc) {
      qDebug() << "SSHのセッションの確立に失敗:" << rc;
      return;
    }
    authenticateUser();
}
void SSHClient::authenticateUser()
{
    int rc = 0;
    do {
      // パスワード認証を行う場合
      rc = libssh2_userauth_password(m_Session, m_User, m_Password);
    } while (rc == LIBSSH2_ERROR_EAGAIN);
    if (rc) {
      qDebug() << "認証に失敗:" << rc;
      return;
    }
    openChannel();
}
void SSHClient::openChannel()
{
    int rc = 0;
    do {
        m_Channel = libssh2_channel_open_session(m_Session);
    } while (m_Channel == nullptr && libssh2_session_last_error(m_Session, nullptr, nullptr, 0) == LIBSSH2_ERROR_EAGAIN);
    if (!m_Channel) {
      qDebug() << "チャンネルのオープンに失敗";
      return;
    }
    executeCommand();
}
void SSHClient::executeCommand()
{
    int rc = 0;
    do {
      rc = libssh2_channel_exec(m_Channel, "ls -la");
    } while (rc == LIBSSH2_ERROR_EAGAIN);
    if (rc) {
      qDebug() << "lsコマンドの実行に失敗:" << rc;
      return;
    }
    // lsコマンドの出力結果を取得を開始
    QTimer::singleShot(0, this, &SSHClient::readOutput);
}
void SSHClient::onReadyRead()
{
    readOutput();
}
void SSHClient::readOutput()
{
    if (!m_Channel) return;
    QByteArray buffer;
    buffer.resize(1024);
    int rc = 0;
    while (rc != LIBSSH2_ERROR_EAGAIN) {
      rc = libssh2_channel_read(m_Channel, buffer.data(), buffer.size());
      if (rc > 0) {
          qDebug().noquote() << QString::fromUtf8(buffer.constData(), rc);
      }
      else if (rc < 0) {
          qDebug() << "チャンネルの読み取りエラー:" << rc;
          closeChannel();
          return;
      }
    }
    // チャンネルがEOFかどうかを確認
    if (libssh2_channel_eof(m_Channel) == 1) {
      closeChannel();
    }
    else {
      // 続きを読み込む
      QTimer::singleShot(0, this, &SSHClient::readOutput);
    }
}
void SSHClient::closeChannel()
{
    if (!m_Channel) return;
    int rc = 0;
    do {
      rc = libssh2_channel_close(m_Channel);
    } while (rc == LIBSSH2_ERROR_EAGAIN);
    if (rc == 0) {
      int exitcode    = libssh2_channel_get_exit_status(m_Channel);
      char *exitsignal = nullptr;
      libssh2_channel_get_exit_signal(m_Channel, &exitsignal, nullptr, nullptr, nullptr, nullptr, nullptr);
      if (exitsignal) {
          qDebug() << "Exit signal:" << exitsignal;
      }
      else {
          qDebug() << "Exit code:" << exitcode;
      }
    }
    libssh2_channel_free(m_Channel);
    m_Channel = nullptr;
    // Disconnect from the host
    m_Socket->disconnectFromHost();
}
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// main.cppファイル
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    SSHClient client;
    client.connectToHost("<リモートPC側のIPアドレスまたはホスト名>", <リモートPCのポート番号>,
                        "<リモートPC側のユーザ名>", "<リモートPC側のユーザパスワード>");
    return a.exec();
}
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
<br><br>

案内メニュー