【问题标题】:Sending commands to server via JSch shell channel通过 JSch shell 通道向服务器发送命令
【发布时间】:2011-05-10 19:34:07
【问题描述】:

我不知道如何通过 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);

【问题讨论】:

  • 错误信息是什么?有堆栈跟踪吗?
  • 没有错误信息,我只是没有收到任何信息。程序停在line = fromServer.readLine(),巫婆的意思是消息还没有发送……至少,我是这么认为的……
  • 希望对您有帮助:jcraft.com/jsch/examples
  • :) 我正在按照这些示例工作... Thnx anw :)
  • jcraft.com/jsch/examples/Shell.java 的示例真的很好用。它只是设置 System.in 和 System.out,它们在管道流和控制台之间找到它们的方式。但是当我通过 ssh 连接到远程主机时,BufferedReader.readLine() 永远不会返回。解决方法是读取大块字节而不是字符串,然后手动从它们构造字符串。

标签: java ssh jsch


【解决方案1】:

试试这个代码:

         JSch jsch=new JSch();

         System.out.println("Getting session");
         Session session=jsch.getSession("root","10.0.0.0",22);

          System.out.println("session is ::::"+session.getHost());
          // username and password will be given via UserInfo interface.
          UserInfo ui = new MyUserInfo("Lab@123", null);
          //UserInfo ui = new MyUserInfo(password, null);
          session.setUserInfo(ui);
          session.setPassword("Lab@123");
          Properties config = new java.util.Properties();
          config.put("StrictHostKeyChecking", "no");
          session.setConfig(config);
          session.connect(40000);


              Channel channel=session.openChannel("exec"); 
              ((ChannelExec)channel).setCommand("ls");

              channel.connect();
              channel.run();

              // get I/O streams for remote scp
              OutputStream out=channel.getOutputStream();
              InputStream in=channel.getInputStream(); 


          String output="";
          while (channel.isClosed()!=true) {

              try {
                output+=streamToString(in);

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

        }

            System.out.println("Output is :::"+output);
            channel.disconnect();
            session.disconnect();
    }

    public static String streamToString(InputStream input)throws Exception 
    { String output = ""; while(input.available()>0) { output += ((char)(input.read())); } return output; }



    public static OutputStream stringToStream(String charset) throws IOException{

        byte[] bytes = charset.getBytes();
        /*ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        InputStreamReader isr = new InputStreamReader(bais);*/
        InputStream is = null;
        OutputStream os = null;
        try {
            is = new ByteArrayInputStream(charset.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //byte[] buf = new byte[1024];
        int numRead;

          while ( (numRead = is.read(bytes) ) >= 0) {
              os.write(bytes, 0, numRead);
          }        
        return os;      

【讨论】:

  • API 说 channel.run() 不应该被调用:here
【解决方案2】:

如果它挂在readLine(),这意味着您的“while”永远不会结束(考虑到您的代码可能不太可能),或者,readLine() 正在等待它的源,即IOstream 阻塞线程导致@ 987654324@。

如果没有看到您的调试信息,我无法对您的代码进行故障排除。但作为一个建议,你试过PipedIntputStream吗?这个想法是将您的控制台输入通过管道传输到“您的”输出,以便您可以“编写”它。要实现这一点,您需要初始化输入/输出。

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”,请确保在 while 中执行某些操作以防止 1)忙等待 2)结束条件。示例:

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

【讨论】:

  • 最后一部分没看懂。位置“32”是任意的吗?是否可以在当前位置设置标记并稍后重置?
  • @Kariem 32 是 32 个字节作为标记缓冲区。已经好几年了,所以我不记得为什么我使用 32 而不是 4。4 应该足够大以容纳一个 read() 但也许我的理由是设置更大并不会损害逻辑。
【解决方案3】:

试试这个:

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());
}

【讨论】:

  • 关于if (i &lt; 0) break;这一行,在确保输入流有可用数据后,读取这个数据会不会返回一个负数表示读取的数据量?!为什么它首先表明它有可用的数据?!
  • 此代码有时会在第一个 while 循环内的 rpm 安装中挂起。
【解决方案4】:

以下是我的作业快速编写的代码。不是一个做得好的程序。 但服务于它的目的。

  1. 通过 SSH(使用 Jsch)连接到服务器(使用私钥文件 - mykey.pem)
  2. 创建一个 shell 脚本(挂载一个卷和 mkfs)
  3. 在远程机器上运行
  4. 您始终可以在标准输出上看到输出

代码如下:

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();
    }

}

}

【讨论】:

    【解决方案5】:

    使用管道输入和输出流看起来很有趣:

    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");
    

    【讨论】:

      【解决方案6】:

      试试这个

      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();   
               }
      

      【讨论】:

        【解决方案7】:
        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;
        }
        

        【讨论】:

          【解决方案8】:

          我意识到这是一个旧线程,但我今天遇到了类似的问题。 这是我的解决方案。

          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")

          【讨论】:

            【解决方案9】:

            用法:

            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);
            

            Implementation

            【讨论】:

              【解决方案10】:

              使用 JSch 时,您必须使用 InputStream 从 SSH 客户端到服务器进行通信,并使用 OutputStream 从服务器返回到客户端。这可能不是很直观。

              以下示例使用管道流来提供更灵活的 API。

              创建一个 JSch 会话 ...

              Session session = new JSch().getSession("user", "localhost", port);
              session.setPassword("secret");
              session.setConfig("StrictHostKeyChecking", "no");
              session.connect();
              

              如果你想向一个 shell 发送多个命令,你应该使用ChannelShell,如下所示:

              ChannelShell channel = (ChannelShell) session.openChannel("shell");
              PipedInputStream pis = new PipedInputStream();
              channel.setInputStream(pis);
              PipedOutputStream pos = new PipedOutputStream();
              channel.setOutputStream(pos);
              channel.connect();
              
              BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new PipedOutputStream(pis)));
              writer.write("echo Hello World\n");
              writer.flush();
              
              BufferedReader reader = new BufferedReader(new InputStreamReader(new PipedInputStream(pos)));
              String line = reader.readLine(); // blocking IO
              
              assertEquals("Hello World", line);
              

              ByteArrayOutputStream 的帮助下,您还可以以非阻塞方式进行通信:

              ChannelShell channel = (ChannelShell) session.openChannel("shell");
              channel.setInputStream(new ByteArrayInputStream("echo Hello World\n".getBytes()));
              ByteArrayOutputStream baos = new ByteArrayOutputStream();
              channel.setOutputStream(baos);
              channel.connect();
              
              sleep(1000); // needed because of non-blocking IO
              String line = baos.toString();
              
              assertEquals("Hello World\n", line);
              

              如果您只想发送一个命令,ChannelExec 就足够了。如您所见,输出流的工作方式与以前相同:

              ChannelExec channel = (ChannelExec) session.openChannel("exec");
              channel.setCommand("echo Hello World");
              PipedOutputStream pos = new PipedOutputStream();
              channel.setOutputStream(pos);
              channel.connect();
              
              BufferedReader reader = new BufferedReader(new InputStreamReader(new PipedInputStream(pos)));
              String line = reader.readLine(); // blocking IO
              
              assertEquals("Hello World", line);
              

              【讨论】:

                猜你喜欢
                • 2013-05-04
                • 1970-01-01
                • 2021-01-17
                • 1970-01-01
                • 2011-08-15
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-04-01
                相关资源
                最近更新 更多