以下是我的Java代码:
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("nohup java -jar /root/xxxx.jar &");
可以执行这个命令,我可以看到服务已经启动,但我没有看到nohup日志(log),为什么会这样?
以下是我的Java代码:
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("nohup java -jar /root/xxxx.jar &");
可以执行这个命令,我可以看到服务已经启动,但我没有看到nohup日志(log),为什么会这样?
Short story个
您的期望是基于与Java实际上无关的观察结果,基本上("将输出重定向到nohup.out
")不起作用,因为通过java.lang.Runtime#exec
产生的进程没有绑定到tty
,因此nohup
wrapper
没有任何影响.
Long story个
Q:当UNIX
个人想要产生长时间运行的进程/程序时,为什么他们需要使用nohup
wrapper
?
当我们从shell
开始工作时,它的前三个文件描述符(stdin
、stdout
和stderr
)被绑定到tty
,例如:
]# ls -la /proc/self/fd/[0-2]
lrwx------ 1 root root 64 Aug 20 09:29 /proc/self/fd/0 -> /dev/pts/2
lrwx------ 1 root root 64 Aug 20 09:29 /proc/self/fd/1 -> /dev/pts/2
lrwx------ 1 root root 64 Aug 20 09:29 /proc/self/fd/2 -> /dev/pts/2
从shell
派生的任何进程都继承这三个文件描述符,例如:
# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
...
# another shell
# 65681 - pid of ping
# 65654 - pid of shell (parent)
]# ps -ef | grep ping
root 65681 65654 0 09:31 pts/2 00:00:00 ping 8.8.8.8
root 65700 65684 0 09:32 pts/3 00:00:00 grep --color=auto ping
]# ls -la /proc/65681/fd/[0-2]
lrwx------ 1 root root 64 Aug 20 09:32 /proc/65681/fd/0 -> /dev/pts/2
lrwx------ 1 root root 64 Aug 20 09:32 /proc/65681/fd/1 -> /dev/pts/2
lrwx------ 1 root root 64 Aug 20 09:32 /proc/65681/fd/2 -> /dev/pts/2
Q:如果我们留下shell
美元,会发生什么?
]# kill -9 65654
]# ls -la /proc/65681/fd/[0-2]
ls: cannot access /proc/65681/fd/[0-2]: No such file or directory
]# ps -ef | grep 65681
root 65738 65684 0 09:40 pts/3 00:00:00 grep --color=auto 65681
操作系统需要关闭tty
(我们离开了shell
),所以OS
向正在使用(绑定到)该tty
的所有进程发送SIGHUP
信号并关闭tty
nohup
wrapper
的目的如下:
它判断前三个文件描述符(stdin
、stdout
和stderr
)是否绑定到tty
,如果是,则将它们替换为/dev/null
、nohup.out
和nohup.out
:
]# nohup ping 8.8.8.8
nohup: ignoring input and appending output to 'nohup.out'
...
# another shell
# 65767 - pid of ping
# 65752 - pid of shell (parent)
]# ps -ef | grep ping
root 65767 65752 0 09:44 pts/2 00:00:00 ping 8.8.8.8
root 65773 65684 0 09:45 pts/3 00:00:00 grep --color=auto ping
]# ls -la /proc/65767/fd/[0-2]
l-wx------ 1 root root 64 Aug 20 09:45 /proc/65767/fd/0 -> /dev/null
l-wx------ 1 root root 64 Aug 20 09:45 /proc/65767/fd/1 -> /nohup.out
l-wx------ 1 root root 64 Aug 20 09:45 /proc/65767/fd/2 -> /nohup.out
现在,试着"离开"我们的shell
人:
]# kill -9 65752
]# ls -la /proc/65767/fd/[0-2]
l-wx------ 1 root root 64 Aug 20 09:45 /proc/65767/fd/0 -> /dev/null
l-wx------ 1 root root 64 Aug 20 09:45 /proc/65767/fd/1 -> /nohup.out
l-wx------ 1 root root 64 Aug 20 09:45 /proc/65767/fd/2 -> /nohup.out
]# ps -ef | grep ping
root 65767 1 0 09:44 ? 00:00:00 ping 8.8.8.8
root 65781 65684 0 09:46 pts/3 00:00:00 grep --color=auto ping
我们的长时间运行的应用程序继续运行,每个人都很高兴--这是nohup
-wrapper
的魔力.
关于你的问题...
如果您的目标是使用Java
重新实现相同的方法,则需要在Java
中执行相同的操作,而不是依赖nohup
wrapper
,以下是一些示例:
让我们try 使用"朴素"实现,如下所示:
public class Test {
public static void main(String[] args) throws Exception {
Runtime rt = Runtime.getRuntime();
rt.exec("ping 8.8.8.8");
Thread.sleep(1_000_000_000);
}
}
]# $JAVA_HOME/bin/javac Test.java
]# $JAVA_HOME/bin/java -cp . Test
# another shell
# 65890 - pid of ping
# 65873 - pid of java (parent)
]# ps -ef | grep ping
root 65890 65873 0 09:58 pts/2 00:00:00 ping 8.8.8.8
root 65895 65684 0 09:59 pts/3 00:00:00 grep --color=auto ping
]# ls -la /proc/65890/fd/[0-2]
lr-x------ 1 root root 64 Aug 20 09:58 /proc/65890/fd/0 -> pipe:[651007]
l-wx------ 1 root root 64 Aug 20 09:58 /proc/65890/fd/1 -> pipe:[651008]
l-wx------ 1 root root 64 Aug 20 09:58 /proc/65890/fd/2 -> pipe:[651009]
现在,我们看到的不是像"/dev/pt/xxx"这样的文件描述符,而是像pipe:[xxx]
这样奇怪的东西.那是什么?也就是说,UNIX IPC
-子进程通过anonymous pipe向父进程发送数据.匿名管道不是tty
,这就是nohup
wrapper
不会有任何影响的原因,我们可以演示使用shell
(既不是输出中的"nohup.out",也不是"忽略输入并将输出附加到‘nohup.out’"消息):
]# nohup ping 8.8.8.8 </dev/null 2>&1 | cat
^Z
[1]+ Stopped nohup ping 8.8.8.8 < /dev/null 2>&1 | cat
]# ps -ef | grep ping
root 66840 65684 0 12:38 pts/3 00:00:00 ping 8.8.8.8
root 66845 65684 0 12:38 pts/3 00:00:00 grep --color=auto ping
]# ls -la /proc/66840/fd/[0-2]
lr-x------ 1 root root 64 Aug 20 12:38 /proc/66840/fd/0 -> /dev/null
l-wx------ 1 root root 64 Aug 20 12:38 /proc/66840/fd/1 -> pipe:[659814]
l-wx------ 1 root root 64 Aug 20 12:38 /proc/66840/fd/2 -> pipe:[659814]
如果父进程退出,会发生什么情况?实际上,这取决于子进程是否通过anonymous pipe发送数据,但在最坏的情况下,子进程将退出:
]# kill 65873
]# ls -la /proc/65890/fd/[0-2]
]# ps -ef | grep ping
root 66238 65684 0 10:31 pts/3 00:00:00 grep --color=auto ping
获得与nohup
wrapper
类似的行为的唯一可靠方法是在Java端"重新实现"nohup
wrapper
:
import java.io.File;
public class Test {
public static void main(String[] args) throws Exception {
Process process = new ProcessBuilder("ping", "8.8.8.8")
.directory(new File("/tmp"))
.redirectInput(new File("/dev/null"))
.redirectOutput(new File("/tmp/nohup.out"))
.redirectError(new File("/tmp/nohup.out"))
.start();
Thread.sleep(1_000_000_000);
}
}
]# ps -ef | grep ping
root 66394 66377 0 10:37 pts/2 00:00:00 ping 8.8.8.8
root 66398 65684 0 10:37 pts/3 00:00:00 grep --color=auto ping
]# kill 66377
]# ls -la /proc/66394/fd/[0-2]
lr-x------ 1 root root 64 Aug 20 10:37 /proc/66394/fd/0 -> /dev/null
l-wx------ 1 root root 64 Aug 20 10:37 /proc/66394/fd/1 -> /tmp/nohup.out
l-wx------ 1 root root 64 Aug 20 10:37 /proc/66394/fd/2 -> /tmp/nohup.out
]# ps -ef | grep 66394
root 66394 1 0 10:37 pts/2 00:00:00 ping 8.8.8.8
root 66402 65684 0 10:38 pts/3 00:00:00 grep --color=auto 66394
因此,您的Java实现:
nohup java -jar /root/xxxx.jar &
是:
Process process = new ProcessBuilder("java", "-jar", "/root/xxxx.jar")
.redirectInput(new File("/dev/null"))
.redirectOutput(new File("nohup.out"))
.redirectError(new File("nohup.out"))
.start();