👋

[C++]Pythonに追いつきたい!2 自作プログラムでSSH接続する

2024/06/23に公開

この記事の対象読者

Pythonparamikoモジュールの使われ方を見たとき、「えっ、こんな手軽にSSHが使えるんだ!」と、感じた事はないでしょうか?「C++で、ワンポイントで手軽にSSHを使いたい。」そんなニッチな方向けの記事です。ちなみに、C++でがっつりSSHを使いたい人向けには、libssh2というライブラリが公開されていますので、こちらをお勧めします。
 また、この技法は、

https://zenn.dev/goldsmith/articles/34a61a41d57641
の、SubProcessクラスを使って構築しています。こちらの記事も、よろしければご覧ください。

仕組みは子プロセスのシェルでSSH接続のスクリプトを実行する

これだけです。

事前準備としてリモートで接続するコンピュータを用意して、鍵認証でログイン出来るようにしておきましょう

ssh リモートホスト名+Enter、または、ssh ユーザー名@リモートホスト名+Enterでログイン出来るようにしておきましょう。


Microsoft Windows [Version 10.0.19045.4529]
(c) Microsoft Corporation. All rights reserved.

C:\Users\usera>

このような画面からssh リモートホスト名(または、IPアドレス)を入力すると、

Microsoft Windows [Version 10.0.22631.3737]
(c) Microsoft Corporation. All rights reserved.

usera@R5600 C:\Users\usera>

と、リモートホストに、繋がればOKです。

デモコードとスクリプト

この記事で使うソースコードへのリンク

GitHubへのリンクはここです。Visual Studio 2022用に設定されたslnファイルもあります。
  TestProjectをスタートアッププロジェクトに設定し、ソリューションエクスプローラーからtest3.cppを選択し、プロパティの設定で全般->ビルドから除外項目をいいえに設定し、test3.cpp以外はいに設定し、ターゲットCPUをx64に設定し、F5を押下すると実行できます。

 ソースコードの中にはデバッグ用のライブラリも含んでいます。本質ではない為、今回は説明を割愛いたします。

この記事で紹介しているソースコードは、公開した時点から変更を加えている事があります。そのため、元の記事とは異なる結果を得る場合があります。また、ソースコードを機能別にディレクトリを分ける等の、改善を行う可能性があります。

デモコード

下記にデモコードを記載します。その後、番号のコメントが付けられているところの、解説を順次していきます。

// test3.cpp
#include "test2.h"
using namespace std;

int main() {
	{
		string str;	// 1
		SubProcess sp;
		if (!sp.Popen(R"(cmd.exe /c RemoteCmd.bat)"))
			return 1;

		sp.SleepEx(2000);// 2
		
		for (; sp.IsActive();) {// 3
			if (sp.IsReadable()) {
				if (!(sp >> cout))
					return 1;
				else
					sp.SleepEx(10);
					continue;

			} else {
				if (!(sp << cin))
					return 1;
				sp.SleepEx(10);
			}
		}

		if (!(sp.WaitForTermination(INFINITE)))// 4
			return 1;

		DWORD dw = sp.GetExitCodeSubProcess();	// 5
		cout << "\nExit code is " << dw << endl;

		sp.Pclose();// 6
	}
	_CrtDumpMemoryLeaks();

}

1、cmd.exeを子プロセスとして起動

		string str;	// 1
		SubProcess sp;
		if (!sp.Popen(R"(cmd.exe /c RemoteCmd.bat)"))
			return 1;

子プロセスとしてcmd.exeを起動と共に、バッチファイルのRemoteCmd.batを実行。バッチファイルの中身は下記のようになっています。

@ssh 192.168.100.205 "cmd.exe" 

注意
 リモートホスト名は、それぞれ自分の環境に、合ったものに書き換えて下さい。

リモートコンピュータでcmd.exeを起動するようにしています。

2、sp.SleepEx(2000)で、リモートホストの接続完了待ち

		sp.SleepEx(2000);// 2

sp.SleepEx(2000)で最大2秒待ちます。それまでに、リモートコンピュータからデータが送られてきたら、それで待ちは終了です。
 接続に成功すると、例えば次のように表示されます。

Microsoft Windows [Version 10.0.22631.3737]
(c) Microsoft Corporation. All rights reserved.

usera@R5600 C:\Users\usera>

3、送信と受信を繰り返す

		for (; sp.IsActive();) {// 3
			if (sp.IsReadable()) {
				if (!(sp >> cout))
					return 1;
				else
					sp.SleepEx(10);
					continue;

			} else {
				if (!(sp << cin))
					return 1;
				sp.SleepEx(10);
			}
		}

ここで、送信と受信を繰り返します。chcpコマンドを入力してみましょう。

usera@R5600 C:\Users\usera>chcp
chcp
݂̃R[h y[W: 932

usera@R5600 C:\Users\usera>

文字化けしていますね・・・。では次に、exitと入力してみましょう。ssh接続が切断されます。

4、切断された後、ローカルのcmd.exeが終了するのを待つ

		if (!(sp.WaitForTermination(INFINITE)))// 4
			return 1;

子プロセスが終了する前に、親プロセスが終了してしまわないようにします。このプロセスを踏んでおかないと、異常終了となる可能性があります。
 このオペレーションが成功すると、

usera@R5600 C:\Users\usera>exit
exit

といった表示が出ます。

5、exitコードを取得する

		DWORD dw = sp.GetExitCodeSubProcess();	// 5
		cout << "\nExit code is " << dw << endl;

exitコードを取得し、表示します。

Exit code is 0

と、表示されます。

6、子プロセス操作ハンドルを閉じる

		sp.Pclose();// 6

これを実行した後は、exitコードは取得できなくなります。この後、SubProcessクラスは別の子プロセスを立ち上げる事が出来ます。

以上で、デモコードの説明終了です

いかがでしたでしょうか。

終わりに

[C++]Pythonに追いつきたい!2 自作プログラムでSSH接続する」の解説は以上となります。この記事が皆様の閃きや発想のきっかけになりましたら幸いです。
 また、ご意見、ご感想、ご質問など、お待ちしております。

Discussion