关于 NodeJS 在 Windows 上杀死启动的进程问题

2022-12-19 20:35:04 +08:00
 FakerLeung

环境:Electron + NodeJS(windows10 ,不考虑 Linux)。

程序是这样的:

  1. node 使用 spawn,传入 execFile (有可能只是个 xxx.bat 脚本)和 args ,启动了一个 java 进程(监听端口 8080 )。
  2. 返回的 child_process 有一个 PID (如 11111 ),但它是属于启动的 cmd 的 PID ,实际 java 进程的 PID 是 22222 。
  3. 退出前,使用 taskkill /T /F /PID 11111,能把这两个进程直接杀掉,但是!该 8080 端口还有很多状态为 TIME_WAIT 的连接没被一同 kill 掉,导致端口一直是被占用的状态。

当然,如果我直接用任务管理器将 java 进程强制终止,那就就没有 TIME_WAIT 的连接了,但是好像没办法使用代码这么干。

求教各位大佬,怎么才能一劳永逸的直接杀死进程。

PS: 并不知道这个进程的名称(就没办法用 taskkill /F /IM ${name} 来杀进程)是啥。

2841 次点击
所在节点    程序员
18 条回复
ysc3839
2022-12-19 20:43:13 +08:00
没理由用 taskkill 杀死后还存在 TIME_WAIT ,但用任务管理器杀死却不存在,这两个工具使用的 API 是一样的,建议仔细检查一下。
macy
2022-12-19 21:28:25 +08:00
我有尝试过使用 fover 来启动这种进程,倒是没发现问题,没有尝试直接用子进程这种启动过,如楼上所说,理论上应该不会出现这种进程,spawn 都挂了,他启动 的进程应该也会挂才对
xuyang2
2022-12-20 09:11:37 +08:00
能用 Java Service Wrapper 将 java 程序设置为服务吗
Java 的服务没必要用 node 管理
FakerLeung
2022-12-20 10:28:20 +08:00
@xuyang2 暂时不能,我们软件是基于 electron 开发的。

@ysc3839 确实是这样子的,就很奇怪。而且如果用 exec 执行 taskkill 有时会出现这种问题:
```
错误:无法终止 PID 11111 (属于 PID 22222 子进程)的进程。
原因:拒绝访问。
错误:无法终止 PID 22222 (属于 PID 33333 子进程)的进程。
原因:拒绝访问。
```

@macy 不知道会不会跟我的 electron 程序会一直请求该 java 程序的心跳接口导致的?
ysc3839
2022-12-20 10:34:29 +08:00
@FakerLeung 此时用任务管理器结束进程情况如何呢?管理员身份运行试试呢?
xuyang2
2022-12-20 10:53:43 +08:00
FakerLeung
2022-12-20 11:21:31 +08:00
@ysc3839 #5
此时这 11111 22222 PID 的进程都没了,但是端口还是占用状态。就是有很多 TIME_WAIT 的连接没释放。


@xuyang2 #6
唉,项目特殊性,不能随便使用没入库的三方件。
ysc3839
2022-12-20 11:24:57 +08:00
@FakerLeung 是任务管理器结束后没了,但仍然占用吗?还是 taskkill ?如果你确定任务管理器和 taskkill 的行为一致,那就是 TCP 栈相关的问题了。
FakerLeung
2022-12-20 11:31:15 +08:00
@ysc3839 #8
taskkill 后,还占用。
任务管理器结束是没问题的。

而且,用 process.kill ,仅能 kill 掉启动的 cmd 进程,无法 kill 掉关联的子进程。
ysc3839
2022-12-20 11:33:15 +08:00
@FakerLeung 那你试过管理员身份运行 taskkill 吗?你确定 taskkill 杀死了进程,而不是像前面那样提示拒绝访问?
FakerLeung
2022-12-20 11:46:03 +08:00
@ysc3839 #10
管理员没试过。

刚试了一下,任务管理器结束也是会有大量 TIME_WAIT 。

TCP 127.0.0.1:11111 127.0.0.1:57438 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57441 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57444 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57447 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57450 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57453 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57456 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57459 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57462 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57465 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57474 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57478 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57481 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57483 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57486 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57489 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57492 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57495 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57498 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57501 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57504 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57509 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57515 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57518 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57521 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57527 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57537 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57540 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57543 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57546 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57550 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57552 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57555 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57558 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57561 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57566 TIME_WAIT 0
TCP 127.0.0.1:11111 127.0.0.1:57769 TIME_WAIT 0
TCP 127.0.0.1:57537 127.0.0.1:11111 TIME_WAIT 0

要等一会(比如 15s ),才会消失。
FakerLeung
2022-12-20 11:46:34 +08:00
@ysc3839 #10
而且 electron 也没办法用管理员运行 taskkill 命令吧。。。
ysc3839
2022-12-20 11:55:05 +08:00
@FakerLeung #11 那说明是 TCP 协议栈的问题了。可以试试这个 https://help.aliyun.com/document_detail/40701.html
#12 测试时当然是手动开个管理员身份的 cmd 来测试。
mmdsun
2022-12-20 13:20:35 +08:00
time_wait 时间可以改小点,然后按端口号批量 kill 进程试试看?

for /f "tokens=5" %%a in ('netstat -aon ^| find ":8080" ^| find "LISTENING"') do taskkill /f /pid %%a
FakerLeung
2022-12-20 14:01:32 +08:00
@ysc3839 #13
不报拒绝访问,但是还是会有 TIME_WAIT 。

@mmdsun #14
改注册表估计不好使哦,因为我们软件要给客户用的,不能随便修改客户机的设置。
ysc3839
2022-12-20 14:22:41 +08:00
还可以试试用 setsockopt 设置 SO_DONTLINGER 和 SO_REUSEADDR
https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-setsockopt#remarks
xyjincan
2022-12-20 16:19:29 +08:00
留个接口让 java 程序自己 exit 0
FakerLeung
2022-12-21 20:06:11 +08:00
@xyjincan
不允许这么干。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/903584

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX