2014-02-06 51 views
0

我想写一个程序,首先ssh'es到两个不同的机器,然后对它们执行一些http请求。这意味着为了能够执行我的http请求,ssh隧道应该正在运行。如何确保主线程仅在子线程启动后才能继续?

我所做的是,我有两个线程,每个线程运行ssh命令框之一:

Thread thread1 = new Thread(new Runnable(){ 
      public void run(){ 
       try{ 
        Process p1 = Runtime.getRuntime().exec("ssh -A -L12345:localhost:54321 firsthost.com"); 
        p1.waitFor(); 
       }catch (Exception e){} 
      } 
     }) ; 
     thread1.start(); 

    Thread thread2 = new Thread(new Runnable(){ 
     public void run(){ 
      try{ 
       Process p2 = Runtime.getRuntime().exec("ssh -A -L12345:localhost:54321 secondhost.com"); 
       p2.waitFor(); 
      }catch (Exception e){} 
     } 
    }) ; 
    thread2.start(); 

现在的问题是,启动线程之后,他们并不总是立即开始运行这意味着我将在连接之前发送我的请求。有没有一种简单的方法(不使用锁或互斥锁),我可以确保在线程启动后我只返回到主程序? (我不想当然等待它们结束,因为它们永远不会结束,只需运行第一个命令:)另外,如果有更好的方法在后台运行进程而不是使用这两个独立的线程,那么太棒了!)

谢谢!

回答

1

尝试添加-f-N标志告诉ssh来的背景本身,一旦端口转发是设置。然后,您可以在主线程中执行ssh命令并等待它们退出(即后台本身),然后再继续。

-f

要求的ssh只是执行命令之前去的背景。如果ssh要求输入密码或密码,但用户希望在后台使用,这很有用。这意味着-n。在远程站点启动X11程序的推荐方法是使用类似ssh -f host xterm的东西。

如果ExitOnForwardFailure配置选项设置为“yes”,那么以-f开头的客户端将等待所有远程端口转发成功建立,然后再将其置于后台。

-N

不要执行远程命令。这仅适用于转发端口(仅限协议版本2)。

(可惜我不能在此刻。道歉,如果它不能正常工作。测试这个)

+0

非常感谢!是的,使用-f和-N它工作。我只需要弄清楚如何避免输入我的密码短语。 (当我从shell执行ssh时,它不会以某种方式提示我的密码,但以这种方式进行。)但除此之外,这是一个非常简单的解决方案:) – N3da

-1

您可以使用thread1.getState()方法来获取线程的状态。在你可以thread1.start()之后,它应该被移动到RUNNABLE状态。当thread1正在等待进程完成时,它将处于BLOCKED状态。

+0

这无助于了解'ssh'是否已成功设置端口转发。 –

+0

你是对的。我误解了这个问题。 –

0

所有使用线程不要直接在JDK5鼓励起的第一位。包装完好的Executors将为我们完成这项工作。如果你有Java的较低版本,或者你想在那么这种方式是怎么做的,这里是一个快速的解决方案,

公共类主要{

public static void main(String... objs) throws Exception { 

    final Process1Thread p1Thread = new Process1Thread(); 
    final Process2Thread p2Thread = new Process2Thread(); 

    Thread p1 = new Thread(p1Thread); 
    Thread p2 = new Thread(p2Thread); 

    p1.start(); p2.start(); 

    while(true) { 
     if(p1Thread.isFinishedCommand() && p2Thread.isFinishedCommand()) { 
      //send commands 
      System.out.println("sending commands"); 
      break; 
     } 
    }  
} 

interface FinishedCommand { 
    boolean isFinishedCommand(); 
} 

static class Process1Thread implements Runnable, FinishedCommand { 

    private boolean finished = false; 

    @Override 
    public boolean isFinishedCommand() { 
     synchronized(this) { 
      return finished; 
     } 
    } 

    @Override 
    public void run() {   
     try { 
      final Process p2 = Runtime.getRuntime().exec("dir"); 

      synchronized(this) { 
       finished = true; 
      }    
      p2.waitFor(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

    }  
} 


static class Process2Thread implements Runnable, FinishedCommand { 

    private boolean finished = false; 

    @Override 
    public boolean isFinishedCommand() { 
     synchronized(this) { 
      return finished; 
     } 
    } 

    @Override 
    public void run() {   
     try { 
      final Process p2 = Runtime.getRuntime().exec("dir"); 

      synchronized(this) { 
       finished = true; 
      }    
      p2.waitFor(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

}

问候 Lyju

相关问题