简体   繁体   English

如何在此处正确关闭 ssh 连接/会话?

[英]how to properly close ssh connection / session here?

I have a client/server socket program.我有一个客户端/服务器套接字程序。 Server part is connecting via ssh to a host, runs a script, and sends each line of the output to the client.服务器部分通过 ssh 连接到主机,运行脚本,并将输出的每一行发送到客户端。

The below server code part returns a BufferedReader containing the script output as it happens:下面的服务器代码部分返回一个包含脚本输出的BufferedReader发生时:

public synchronized BufferedReader runScript(<params>) {    
  BufferedReader br = null ;
  try {
      Connection conn = new Connection(host);
      conn.connect();
      ... // authentication part
      Session sess = conn.openSession();
      sess.execCommand("ascript");
      InputStream stdout = new StreamGobbler(sess.getStdout());
      br = new BufferedReader(new InputStreamReader(stdout));
  } catch (Exception e) {
      e.printStackTrace();
  }
  return br;
}

The above method is called from another server-side class/code as below, writing each line of the BufferedReader to the client through a socket, so that client sees the live output of the script as it runs :上述方法是从另一个服务器端类/代码调用的,如下所示,通过套接字将 BufferedReader 的每一行写入客户端,以便客户端在运行时看到脚本的实时输出:

BufferedReader br = new UnixCommandExecutor().runScript(<params>);
String line;
while ((line = br.readLine()) != null) {
      out.writeObject(line);
}

The obvious problem with runScript method is that it doesn't close the ssh Connection & Session (ganymed ssh lib), as it instantly returns the BufferedReader (if I'm not mistaken) while the underlying script still runs . runScript 方法的明显问题是它不会关闭 ssh 连接和会话(ganymed ssh lib),因为它会立即返回 BufferedReader(如果我没记错的话),而底层脚本仍在运行。 If I close these before the return statement, the BufferedReader would be incomplete.如果我在 return 语句之前关闭它们,BufferedReader 将不完整。 So how do I properly close connection/session here as soon as the underlying script completes ?那么如何在底层脚本完成后立即正确关闭连接/会话?

(I'm aware of try-with-resources and will use it, however I doubt it will solve the problem completely?) (我知道 try-with-resources 并且会使用它,但是我怀疑它能否完全解决问题?)

I would suggest that you refactor the code, so that you我建议你重构代码,这样你

  • either wrap the parts into an object and handling the close operation later要么将部件包装成一个对象并稍后处理关闭操作
  • or you consume the Reader immediately and close the connection after you are done with it.或者您立即使用阅读器并在完成后关闭连接。

Do not pass the Reader to the outside without maintaining the connection.请勿在未保持连接的情况下将 Reader 传递到外部。

Below a somewhat simplified example on how it could be done.下面是一个关于如何完成的简化示例。

If you need to process through mutliple steps before your are done with the Reader, you might not be able to wrap the ResultHandler in a try { ... } catch block.如果在完成 Reader 之前需要通过多个步骤进行处理,则可能无法将 ResultHandler 包装在 try { ... } catch 块中。 In that case you need a different meachnism to ensure that this will eventually be closed.在这种情况下,您需要一个不同的机制来确保这最终会被关闭。

But judging from your problem description that might not be the case.但从你的问题描述来看,可能并非如此。

If you do not want to block till the operation is done (anyway this operation is something that should be executed in a background thread), then you probably want to send each output line you receive to somewhere where it can be displayed.如果您不想阻塞直到操作完成(无论如何,此操作应该在后台线程中执行),那么您可能希望将收到的每个输出行发送到可以显示的地方。 In this case you can should provide an interface that you use to forward the received lines.在这种情况下,您应该提供一个用于转发接收到的线路的接口。

While the reader still receives output (as long as the input stream / connection is active) you`ll probably need to loop.虽然阅读器仍然接收输出(只要输入流/连接处于活动状态),您可能需要循环。 Somehow you need to figure out when your operation is completed.不知何故,您需要弄清楚您的操作何时完成。

For example your script could close the connection (from the serverside) once it is done or return something specific to you that you can interpret as end of operations.例如,您的脚本可以在完成后关闭连接(从服务器端)或返回特定于您的内容,您可以将其解释为操作结束。

public class ResultHandler {

    String host;
    Connection conn;
    BufferedReader reader = null;

    public ResultReader(String host) {
        this.host = host;
    }

    public void connect(<params>) throws Exception {

        // if you intend to reuse the object, just check that it was properly cleanedup before
        close();

        conn = new Connection(host);
        conn.connect();
        ... // authentication part

        // you might want to move the actual handling to a different method
        Session sess = conn.openSession();
        sess.execCommand("ascript");
        InputStream stdout = new StreamGobbler(sess.getStdout());
        br = new BufferedReader(new InputStreamReader(stdout));
    }

    public BufferedReader getReader() {
        return this.reader;
    }

    public void close() {
        If (reader != null) {
            reader.close();
        }
        if (conn != null) {
            conn.close();
        }
    }

    public void finalize() {
        close();
    }
}


synchronized void runScript(<params>) {    

  ResultHandler handler;
  try {
        handler = new ResultHandler(host);
        handler.connect();

        // consume the reader for whatever you need to do

  } catch (Exception e) {
      e.printStackTrace();
  } finally {
    // or use try-with-resource and implement the proper interface for that
    if (handler != null) {
        handler.close();
     }
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM