expect 4 j使用心得

3349 ワード

実際の生産プロジェクトでは、多くのヒューマンマシンのインタラクションが含まれています.このとき、プログラムが自主的にいくつかの動作を完成したい場合は、ログインパスワードを入力したり、砦機とインタラクションしたりするのが面倒です.これらの機能を実現するためにexpect 4 jを適用する方法について説明します.
    expect 4 jも同様にsshプロトコルに基づいており、彼の下層はjschパケットに依存しているが、本質的にはjschが作成したチャネルストリームを処理し、事前にclosureを設定し、マッチングしたら次の操作を行い、自動的にクラス命令をインタラクティブに完了する機能を達成している.コードを直接見て、まずsessionを作成します.
private static Session getSession(String usr,String ip,String pwd) throws JSchException {
		Session session = null;
		try {
			JSch jsch = new JSch();
			session = jsch.getSession(usr, ip, 22);
			Properties config = new Properties();
			config.put("StrictHostKeyChecking", "no");
			session.setConfig(config);
			session.setPassword(pwd);
			session.connect(3000);
		} catch (JSchException e) {
			if (session != null) {
				session.disconnect();
				session = null;
			}
			throw e;

		}
		return session;
	}

    次にセッションを使用してshell channelを開き、channelストリームをexpect 4 jに提供し、expectクライアントを作成します.
ChannelShell channel = (ChannelShell) session.openChannel("shell");
Expect4j expect = new Expect4j(channel.getInputStream(), channel.getOutputStream());
channel.connect(3000);

    次はメインイベントです.expectに前のコマンドが実行されたかどうかを知らせる方法です.この場合、次のコマンドを実行できることを示すプロンプトを示すために、いくつかの終端子を定義する必要があります.コードを見てみましょう
	public static List getPattern(List promptRegEx, StringBuffer buffer)
			throws MalformedPatternException {
		List lstPattern = new ArrayList();
		synchronized (promptRegEx) {
			for (String regexElement : promptRegEx) {
				RegExpMatch mat = new RegExpMatch(regexElement, x -> {
					buffer.append(x.getBuffer());
					// x.exp_continue();
				});
				lstPattern.add(mat);
			}
		}
		lstPattern.add(new TimeoutMatch(DEFAULTTIMEOUT, x -> {
		}));
		return lstPattern;
	}        

    上記の関数のpromptRegExはカスタムの終端であり、一般的には~や$などのオペレーティングシステムのプロンプトである.非常に重要な点は、特殊な文字は$のように、必ず$と書かなければならないことです.もちろんJAVAでは2つの反スラッシュが必要です.bufferはインタラクション中のすべての操作と結果レコードであり、最後にbuffer.toStringによってすべての結果を返すことができます.プログラムの中で私は1行注釈した. x.exp_continue()は、この表現が終了符に一致しても、彼は次から次へと一致し続けることを示しています.個人的にはこれはあまり役に立たないし、性能に非常に影響していると思いますので、コメントしましたが、ネット上の他の多くの場所にこの文が追加されています.
    もう1つは、命令実行中にネットワークの問題や他の未知の問題が発生してカードが詰まった場合、プログラムでタイムアウトのclosureであるTimeoutMatchを追加定義したことを見ることができ、このタイムアウト時間は自分で設定することができます.
    以下に具体的なインタラクティブコマンドを実行します.サンプルプログラムは以下の通りです.
List lstPattern = getPattern(promptRegEx, buffer);
expect.expect(lstPattern);
expect.send(cmd1);
expect.expect(lstPattern);
expect.send(cmd2);
expect.expect(lstPattern);

    expect関数は、一致する結果が何回目に見つかったか、エラーコードが戻ったことを示すint結果を返す終了子を探す操作です.send関数は命令を送信して実行します.命令の後ろに改行をつけて、実行を表します.そうしないと実行しません.
    最後に実行結果を取得して、上のbufferを直接toStringすればいいです.リモートマシンの戻り結果に中国語があり、使用する符号化が現在のホスト環境変数の使用符号化と一致しない場合、文字化けしてしまうことに注意してください.解決策は、現在のホストのデフォルト符号化を修正し、本当に修正しにくい場合は、expect 4 jソース符号を修正して変更することができ、彼のソース符号化で使用される符号化は取得したホストのデフォルト符号化であり、実際には手動で自分で設定することができる.例:
/** Creates a new instance of ReaderConsumer */
	public StreamPair(InputStream is, OutputStream os) {
		try {
			this.is = new InputStreamReader(is, "GBK");
			this.os = new OutputStreamWriter(os, "GBK");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	}