web-dev-qa-db-ja.com

JSchシェルチャネルを介してサーバーにコマンドを送信する

JSch Shellチャネルを介してコマンドを送信する方法がわかりません。

私はこれを行いますが、うまくいきません:

JSch Shell = new JSch();
String command = "cd home/s/src";  
Session session = Shell.getSession(username, Host, port);  
MyUserInfo ui = new MyUserInfo();  
ui.setPassword(password);  
session.setUserInfo(ui);  
session.connect();  

channel = session.openChannel("Shell");  
fromServer = new BufferedReader(new InputStreamReader(channel.getInputStream()));  
toServer = channel.getOutputStream();
channel.connect();  
toServer.write((command + "\r\n").getBytes());
toServer.flush();

そして、私はこのような入力を読みます:

StringBuilder builder = new StringBuilder();  

int count = 0;  
String line = "";  

while(line != null) {  
    line = fromServer.readLine();
    builder.append(line).append("\n");

    if (line.endsWith(".") || line.endsWith(">")){
        break;
    }
}  
String result = builder.toString();  
ConsoleOut.println(result);
25
Nezzit

readLine()でハングする場合、 "while"が終了しない(コードを考慮する可能性が低い)か、readLine()がそのソース、つまりIOstreamは、スレッドの原因available()!=trueをブロックします。

デバッグ情報を見ずにコードのトラブルシューティングを行うことはできません。しかし、アドバイスとして、PipedIntputStreamを試しましたか?アイデアは、コンソール入力を「your」出力にパイプして、「write」できるようにすることです。これを実装するには、入力/出力を初期化する必要があります。

InputStream in = new PipedInputStream();
PipedOutputStream pin = new PipedOutputStream((PipedInputStream) in);
/**...*/
channel.setInputStream(in);
channel.connect();
/** ...*/
pin.write(myScript.getBytes());

同じことがコンソール出力の読み方の質問にも当てはまります。

PipedInputStream pout = new PipedInputStream((PipedOutputStream) out);
/**
* ...
*/
BufferedReader consoleOutput = new BufferedReader(new InputStreamReader(pout));
consoleOutput.readLine();

繰り返しますが、読み込む行数がわからないため「while」を使用する場合は、1)ビジー待機2)終了条件を防ぐために、しばらくの間、何かを行うようにしてください。例:

while(!end)
{
   consoleOutput.mark(32);
   if (consoleOutput.read()==0x03) end = true;//End of Text
   else
   { 
     consoleOutput.reset();
     consoleOutput.readLine();
     end = false;
   }
}
11
nilbot

これを試して:

JSch jsch = new JSch();

try
{
  Session session = jsch.getSession("root", "192.168.0.1", 22);
  Java.util.Properties config = new Java.util.Properties();
  config.put("StrictHostKeyChecking", "no");
  session.setConfig(config);

  session.connect();

  String command = "lsof -i :80";
  Channel channel = session.openChannel("exec");
  ((ChannelExec) channel).setCommand(command);
  channel.setInputStream(null);
  ((ChannelExec) channel).setErrStream(System.err);
  InputStream in = channel.getInputStream();

  channel.connect();

  byte[] tmp = new byte[1024];
  while (true)
  {
    while (in.available() > 0)
    {
      int i = in.read(tmp, 0, 1024);
      if (i < 0)
        break;
      System.out.print(new String(tmp, 0, i));
    }
    if (channel.isClosed())
    {
      System.out.println("exit-status: " + channel.getExitStatus());
      break;
    }
    try
    {
      Thread.sleep(1000);
    }
    catch (Exception ee)
    {
    }
  }

  channel.disconnect();
  session.disconnect();
}
catch (Exception e)
{
  System.out.println(e.getMessage());
}
18
private void executeRemoteCommandAsSudo(String sudoAs, String password,
            String command, int delayInSeconds) 
{
    logger.info("executeRemoteCommandAsSudo started....");
    logger.info("sudoAs=" + sudoAs);
    logger.info("command=" + command);
    logger.info("delayInSeconds=" + delayInSeconds);
    Session session = null;
    Channel channel = null;
    try {
        session = getSession();
        channel = session.openChannel("exec");
        String sudoCommand = "Sudo su - " + sudoAs;
        ((ChannelExec) channel).setCommand(sudoCommand);
        ((ChannelExec) channel).setPty(true);
        channel.connect();
        InputStream inputStream = channel.getInputStream();
        OutputStream out = channel.getOutputStream();
        ((ChannelExec) channel).setErrStream(System.err);
        out.write((password + "\n").getBytes());
        out.flush();
        Thread.sleep(1000);
        out.write((command + "\n").getBytes());
        out.flush();
        Thread.sleep(1000 * delayInSeconds);
        out.write(("logout" + "\n").getBytes());
        out.flush();
        Thread.sleep(1000);
        logInfo(channel, inputStream);
        out.write(("exit" + "\n").getBytes());
        out.flush();
        out.close();
        Thread.sleep(1000);
    } catch (Exception ex) {
        logger.error(ex.getMessage());
    } finally {
        session.disconnect();
        channel.disconnect();
    }
    logger.info("executeRemoteCommandAsSudo completed....");
}
private void logInfo(Channel channel, InputStream in) 
{
    try {
        byte[] tmp = new byte[1024];
        while (true) {
            while (in.available() > 0) {
                int i = in.read(tmp, 0, 1024);
                if (i < 0)
                    break;
                logger.info(new String(tmp, 0, i));
            }
            if (channel.isClosed()) {
                logger.info("exit-status: " + channel.getExitStatus());
                break;
            }
        }
    } catch (Exception ex) {
        logger.error(ex);
    }
}

private Session getSession() throws JSchException 
{
    JSch jsch = new JSch();
    logger.info("ftpUser=" + ftpUser);
    logger.info("ftpHost=" + ftpHost);
    Session session = jsch.getSession(ftpUser, ftpHost, 22);
    session.setPassword(ftpPassword);
    Java.util.Properties config = new Java.util.Properties();
    config.put("StrictHostKeyChecking", "no");
    session.setConfig(config);
    session.connect();
    return session;
}
2
user1345691

以下は、私の割り当てのために素早く書かれたコードです。よくできたプログラムではありません。しかし、その目的を果たします。

  1. SSHを介して(Jschを使用して)サーバーに接続します(秘密鍵ファイル-mykey.pemを使用)
  2. シェルスクリプトを作成します(ボリュームとmkfsをマウントするため)
  3. リモートマシンで実行
  4. その間、stdoutで出力を確認できます

コードは次のとおりです。

public class connectSSH {

public void connect(String dnsName, String privKey) throws IOException {
    JSch jSch = new JSch();

    try {

                    //Authenticate through Private Key File
        jSch.addIdentity(privKey);
                    //Give the user and dnsName
        Session session = jSch.getSession("root", dnsName, 22);
                    //Required if not a trusted Host
        Java.util.Properties config = new Java.util.Properties(); 
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        System.out.println("Connecting SSH to " + dnsName + " - Please wait for few minutes... ");
        session.connect();
            //Open a Shell 
        Channel channel=session.openChannel("Shell");
        channel.setOutputStream(System.out);
            //Create a Shell Script
        File shellScript = createShellScript();
            //Convert the Shell script to byte stream
        FileInputStream fin = new FileInputStream(shellScript);
        byte fileContent[] = new byte[(int)shellScript.length()];
        fin.read(fileContent);
        InputStream in = new ByteArrayInputStream(fileContent);
            //Set the Shell script to the channel as input stream
        channel.setInputStream(in);
            //Connect and have fun!
        channel.connect();          

    } catch (JSchException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

public File createShellScript() {
     String filename = "shellscript.sh";
     File fstream = new File(filename);

     try{
          // Create file 
         PrintStream out = new PrintStream(new FileOutputStream(fstream));
         out.println("#!/bin/bash");
         out.println("echo \"hi\" > /tmp/test.info");
         out.println("echo \"n\" > /tmp/fdisk.in");
         out.println("echo \"p\" >> /tmp/fdisk.in");
         out.println("echo \"1\" >> /tmp/fdisk.in");
         out.println("echo >> /tmp/fdisk.in");
         out.println("echo >> /tmp/fdisk.in");
         out.println("echo \"w\" >> /tmp/fdisk.in");

         out.println("/sbin/fdisk /dev/sdf < /tmp/fdisk.in");
         out.println("mkfs.ext3 /dev/sdf1");
         out.println("mkdir /usr/myebs");
         out.println("mount /dev/sdf1 /usr/myebs");
         out.println("partprobe /dev/sdf1");

         out.println("echo \"Success\"");

         //Close the output stream
         out.close();
     }catch (Exception e){//Catch exception if any
         System.err.println("Error: " + e.getMessage());
     }
     return fstream;

}

public static void main(String[] args) {
    connectSSH ssh = new connectSSH();
    String privKey = "/Users/neo/Desktop/mykey.pem";
    try {
        ssh.connect("yourexampleserver.com", privKey);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

}
2
neosab

これは古いスレッドであることを認識していますが、今日は同様の問題に苦労しています。これが私の解決策です。

_public class ChannelConsole {

// ================================================
// static fields
// ================================================

// ================================================
// instance fields
// ================================================

private Session session;

// ================================================
// constructors
// ================================================

public ChannelConsole(Session session) {
    this.session = session;
}

// ================================================
// getters and setters
// ================================================

// ================================================
// public methods
// ================================================

public String execute(String command) throws JSchException {
    command = command.trim() + "\n";

    ChannelExec channel = (ChannelExec) this.session.openChannel("exec");
    channel.setCommand(command);

    ByteArrayOutputStream responseStream = new ByteArrayOutputStream();
    channel.setOutputStream(responseStream);

    channel.connect();

    try {
        awaitChannelClosure(channel);
    } catch (InterruptedException e) {
        // no one cares
    }

    String result = responseStream.toString();
    closeQuietly(responseStream);
    return result;

}

// ================================================
// private methods
// ================================================

private void awaitChannelClosure(ChannelExec channel) throws InterruptedException {
    while (channel.isConnected()) {
        Thread.sleep(100);
    }
}

private static void closeQuietly(Closeable closeable) {
    if (closeable == null) {
        return;
    }

    try {
        closeable.close();
    } catch (IOException ignored) {
        ignored.printStackTrace();
    }
}

}
_

このクラスを使用すると、次のようなことができます:Shell = new ChannelConsole(this.session); String result = Shell.execute("quota -v; echo; echo \"Disk storage information:\"; df -hk")

1
Apokralipsa

パイプ入力および出力ストリームでは興味深いようです:

JSch jsch = new JSch();
jsch.addIdentity("/home/audrius/.ssh/blablabla", "blablablabla");

String user = "audrius";
String Host = "ultrastudio.org";

Session session = jsch.getSession(user, Host, 439);
session.setConfig("StrictHostKeyChecking", "no");           
session.connect();

Channel channel = session.openChannel("Shell");

PipedInputStream pip = new PipedInputStream(40);
channel.setInputStream(pip);

PipedOutputStream pop = new PipedOutputStream(pip);
PrintStream print = new PrintStream(pop);           
channel.setOutputStream(System.out);

print.println("ls");
1
audriusa

使用法:

String remoteCommandOutput = exec("ssh://user:pass@Host/work/dir/path", "ls -t | head -n1");
String remoteShellOutput = Shell("ssh://user:pass@Host/work/dir/path", "ls")
Shell("ssh://user:pass@Host/work/dir/path", "ls", System.out)
Shell("ssh://user:pass@Host", System.in, System.out);

実装

0

これを試して

Channel channel=session.openChannel("Shell");
            OutputStream ops = channel.getOutputStream();
        PrintStream ps = new PrintStream(ops, true);

         channel.connect();
         ps.println("mkdir folder"); 
         ps.println("dir");
 //give commands to be executed inside println.and can have any no of commands sent.
                      ps.close();

         InputStream in=channel.getInputStream();
         byte[] bt=new byte[1024];


         while(true)
         {

         while(in.available()>0)
         {
         int i=in.read(bt, 0, 1024);
         if(i<0)
          break;
            String str=new String(bt, 0, i);
          //displays the output of the command executed.
            System.out.print(str);


         }
         if(channel.isClosed())
         {

             break;
        }
         Thread.sleep(1000);
         channel.disconnect();
         session.disconnect();   
         }
0
krishna