2011-04-29 840 views
11

我試圖通過使用JSch庫的SSH協議執行多個命令。但我似乎卡住了,找不到任何解決方案。 setCommand()方法只能在每個會話中執行單個命令。但我想按照Android平臺上的connectbot應用程序的順序執行這些命令。到目前爲止,我的代碼是:通過Jsch Shell執行多個命令

package com.example.ssh; 

import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.util.Properties; 

import android.app.Activity; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.EditText; 
import android.widget.TextView; 
import android.widget.Toast; 

import com.jcraft.jsch.Channel; 
import com.jcraft.jsch.JSch; 
import com.jcraft.jsch.JSchException; 
import com.jcraft.jsch.Session; 

public class ExampleSSH extends Activity { 
    /** Called when the activity is first created. */ 
    EditText command; 
    TextView result; 
    Session session; 
    ByteArrayOutputStream baos; 
    ByteArrayInputStream bais; 
    Channel channel; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     bais = new ByteArrayInputStream(new byte[1000]); 
     command = (EditText) findViewById(R.id.editText1); 
     result = (TextView) findViewById(R.id.terminal); 
    } 

    public void onSSH(View v){ 
     String username = "xxxyyyzzz"; 
     String password = "aaabbbccc"; 
     String host  = "192.168.1.1"; // sample ip address 
     if(command.getText().toString() != ""){ 
      JSch jsch = new JSch(); 
      try { 
       session = jsch.getSession(username, host, 22); 
       session.setPassword(password); 

       Properties properties = new Properties(); 
       properties.put("StrictHostKeyChecking", "no"); 
       session.setConfig(properties); 
       session.connect(30000); 

       channel = session.openChannel("shell"); 
       channel.setInputStream(bais); 
       channel.setOutputStream(baos); 
       channel.connect(); 

      } catch (JSchException e) { 
       // TODO Auto-generated catch block 
       Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); 
      } 
     } 
     else{ 
      Toast.makeText(this, "Command cannot be empty !", Toast.LENGTH_LONG).show(); 
     } 
    } 

    public void onCommand(View v){ 
     try { 
      bais.read(command.getText().toString().getBytes()); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     baos = new ByteArrayOutputStream(); 
     channel.setOutputStream(baos); 
     result.setText(baos.toString()); 

    } 
} 

代碼似乎可以連接到服務器,但我認爲有一些問題,輸入和輸出數組緩衝區,因爲有沒有輸出。有人可以請指導我如何妥善處理輸入和輸出到服務器以獲得所需的輸出?

回答

12

該命令是一個字符串,可以是遠程shell接受的任何東西。嘗試

cmd1 ; cmd2 ; cmd3 

按順序運行幾個命令。或者

cmd1 && cmd2 && cmd3 

運行命令直到一個失敗。

即使這可能工作:

cmd1 
cmd2 
cmd3 

或Java中:

channel.setCommand("cmd1\ncmd2\ncmd3"); 

旁註:不要把密碼和用戶名到代碼。將它們放入屬性文件並使用系統屬性指定屬性文件的名稱。這樣,您可以將文件保存在項目之外,並確保密碼/用戶名不會泄漏。

11

如果您不需要區分單個命令的輸入或輸出,那麼來自Aaron的回答(給出連續的所有命令,用\n;分隔)是很好的。

如果您必須單獨處理它們,或者在先前的命令完成之前不知道以後的命令:您可以在同一會話(即連接)上一個接一個地打開多個exec-Channels(即在一個之後之前被關閉)。每個人都有自己的命令。 (但他們不共享的環境,所以在第一個的cd命令對後來者沒有任何影響。)

您只需照顧到周圍有Session對象,而不是爲每個新命令。

另一種選擇是shell channel,然後將各個命令作爲輸入(即通過流)傳遞給遠程shell。但是,你必須注意不要將輸入與下一個命令混合在一個命令中(例如,只有當你知道命令正在做什麼,或者如果你有一個交互式用戶可以提供輸入到命令和下一個命令,並知道哪一個將被使用。)

+0

這是怎麼完成的任何例子? – Pixie 2016-06-02 15:49:14

4

設置一個SCPInfo對象來保存用戶名,密碼,端口:22和ip。

List<String> commands = new ArrayList<String>(); 
    commands.add("touch test1.txt"); 
    commands.add("touch test2.txt"); 
    commands.add("touch test3.txt"); 
    runCommands(scpInfo, commands); 

public static void runCommands(SCPInfo scpInfo, List<String> commands){ 
    try { 
     JSch jsch = new JSch(); 
     Session session = jsch.getSession(scpInfo.getUsername(), scpInfo.getIP(), scpInfo.getPort()); 
     session.setPassword(scpInfo.getPassword()); 
     setUpHostKey(session); 
     session.connect(); 

     Channel channel=session.openChannel("shell");//only shell 
     channel.setOutputStream(System.out); 
     PrintStream shellStream = new PrintStream(channel.getOutputStream()); // printStream for convenience 
     channel.connect(); 
     for(String command: commands) { 
      shellStream.println(command); 
      shellStream.flush(); 
     } 

     Thread.sleep(5000); 

     channel.disconnect(); 
     session.disconnect(); 
    } catch (Exception e) { 
     System.err.println("ERROR: Connecting via shell to "+scpInfo.getIP()); 
     e.printStackTrace(); 
    } 
} 

private static void setUpHostKey(Session session) { 
    // Note: There are two options to connect 
    // 1: Set StrictHostKeyChecking to no 
    // Create a Properties Object 
    // Set StrictHostKeyChecking to no 
    // session.setConfig(config); 
    // 2: Use the KnownHosts File 
    // Manually ssh into the appropriate machines via unix 
    // Go into the .ssh\known_hosts file and grab the entries for the hosts 
    // Add the entries to a known_hosts file 
    // jsch.setKnownHosts(khfile); 
    java.util.Properties config = new java.util.Properties(); 
    config.put("StrictHostKeyChecking", "no"); 
    session.setConfig(config); 
} 
+0

這隻有在命令沒有輸入任何輸入時纔會起作用,否則以下命令將被解釋爲第一個命令的輸入。 – 2012-06-10 13:57:57

+1

太棒了!就是我在找的東西。 – 2016-11-29 16:30:25