我正在为研究项目构建一个配对的客户端/服务器应用程序。服务器端应用程序是一个java二进制文件,它有一个主循环和一个ServerSocket对象。当具有客户端应用程序的用户振铃服务器时,我实例化ClientSession类型的新对象,并为其提供将进行通信的套接字。然后我将它作为一个新线程运行,以便服务器应用程序的中心线程可以返回等待调用。
然后,每个ClientSession线程根据客户端程序的请求进行一些处理。它可能接受一个字符串并返回一个小的SQLite .db文件作为响应,或接受一个不同的字符串并发回一个包含文件列表和文件大小的Java序列化对象。在所有情况下,ClientSession线程都是短暂的,并在关闭套接字时关闭。
到目前为止,这工作正常,但今天我有一个新的挑战,根据客户的要求运行所有东西,perl脚本。该脚本基本上包含了一些对我的问题域有用的低级Unix OS函数。如果客户端发出启动此脚本副本的请求,我不能只在ClientSession线程中启动它。 perl脚本需要在调用的生命周期后保留(可能在使用睡眠计时器的循环中运行数天或数周)。
我想要做的是在我的服务器应用程序上设置一个单独的线程并让它包装这个perl脚本。
Runtime.getRuntime.exec('perl script.pl');
这将启动它,但现在它将因ClientSession线程而死亡。
我的想法就像声明一个PerlThread对象,要求它知道谁将请求新线程作为其构造函数的一部分的UserID,让它实现Runnable接口,然后在一个上执行一个thread.start()新的实例。但在我到达那里之前,我必须在子线程和我的服务器应用程序的主线程之间传递一些消息。所以这个设置让我想到了我的问题:
如何从子线程将消息传递回主服务器程序并告诉客户端请求perl包装器线程启动?
答案 0 :(得分:2)
您应该查看ExecutorService以获得在不同线程上运行作业的更好技巧。它比Thread.start()或Runnable.run()更强大,更方便。
您可以查看Callable构造,了解如何从在其他线程上运行的作业中获取结果。
当您完成特定于域的可调用的构造函数时,您可以将要从该任务返回的信息传递回来,并且当它完成时,您可以将其恢复。
答案 1 :(得分:1)
如何从子线程将消息传递回主服务器程序并告诉客户端请求perl包装器线程启动?
我会在一个包装UserId
以及关联的Process
对象的地方存储一个对象。如果只有其中一个,您可以将其存储在static volatile
字段中。类似的东西:
public class ClientHandler {
...
private static volatile UserProcess userProcess;
...
// client handler
if (userProcess != null) {
// return error that the perl process is already started
} else {
// start the process
Process process = Runtime.getRuntime.exec('perl script.pl');
userProcess = new UserProcess(userId, process);
}
然后主程序可以通过查看ClientHandler.userProcess
来查明是否有任何客户端运行了perl脚本。
如果您可以在客户端上运行多个进程,那么我将围绕这些ProcessManager
对象的集合包装某种UserProcess
类。类似于startProcess(...)
,listProcesses()
,...然后主类会询问ProcessManager
正在运行的进程或用户启动了哪些进程等。
UserProcess
类只是UserId
和Process
字段的包装。