父进程意外被子 cmd 杀死.exe运行 java jar 的进程 - WINDOWS 7 问题 - C++

Parent process unexpectedly killed by child cmd.exe process running java jar - WINDOWS 7 PROBLEM - C++

本文关键字:进程 jar WINDOWS C++ 问题 java 运行 意外 cmd exe 杀死      更新时间:2023-10-16

有关该项目的信息:我正在创建一个C++控制台应用程序,该应用程序通过侦听端动来管理Minecraft服务器。当服务器端口被 ping 时,它会启动服务器,然后定期检查该端口上是否建立了连接。如果没有,服务器将关闭,应用程序将再次进入侦听模式。

服务器停止时出现问题。不知何故,我的主控制台应用程序被子服务器进程杀死了,我似乎无法找出如何以及为什么或任何解决方案。

我的控制台应用程序创建一个新的 cmd.exe 子进程,该子进程在启动服务器时运行"java -jar 服务器.jar"命令。停止服务器时,会将简单的"stop"消息写入子进程的标准输入。这一切都工作正常,java服务器停止。

但是,一旦子进程退出,控制台应用就会意外崩溃,并出现 Windows"程序已停止工作"对话框。奇怪的是,我已经在运行Windows 10的编程笔记本电脑上测试了该应用程序,并且在发布和调试模式下运行没有任何问题。但是,我的服务器机器正在运行Windows 7,因此这似乎在某种程度上是Windows 7的问题。

现在没有代码可以真正向您展示,因为它是执行退出的 java 和 cmd .exe子进程,我当然没有编写服务器.jar文件的代码。但是当控制台崩溃时,我会附加控制台的图像链接,只是为了好玩。

子进程没有单独的窗口,它从父控制台应用继承句柄,并写入父控制台应用的 STDOUT,以便来自子进程的消息显示在主应用的控制台中。

我尝试使用CREATE_NEW_PROCESS_GROUP标志启动子进程,但仍然崩溃。

我尝试忽略SIGINT和SIGTERM信号,仍然崩溃。

我还验证了应用程序在服务器关闭调用(将停止消息写入服务器进程的 stdin(后不会开始执行命令,因此它们不会成为问题。

如果有人对可能是什么问题有任何提示或想法,我会全力以赴。谢谢!

控制台应用程序崩溃,Windows"程序已停止工作"对话框未显示在图片上。

编辑:

好的,所以我创建了一个最小的可重现示例。以下是所有需要的代码(用于C++主函数(:

//security attributes for pipes
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
//handles for child standard input/output
HANDLE child_stdin_rd = NULL;
HANDLE child_stdin_wr = NULL;
if (!CreatePipe(&child_stdin_rd, &child_stdin_wr, &saAttr, 0))
return -1;
if (!SetHandleInformation(child_stdin_wr, HANDLE_FLAG_INHERIT, 0))
return -1;
STARTUPINFOW startupInfo;
ZeroMemory(&startupInfo, sizeof(STARTUPINFOW));
startupInfo.cb = sizeof(STARTUPINFOW);
startupInfo.hStdInput = child_stdin_rd;
startupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
startupInfo.dwFlags |= STARTF_USESTDHANDLES;
PROCESS_INFORMATION processInfo;
ZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION));
//cmd.exe path
wstring exepath = L"c:\windows\system32\cmd.exe";
//cmd command to start server
wstring command = L"cmd.exe /c java -Xms1G -Xmx4G -jar server.jar nogui";
LPWSTR com = new wchar_t[command.size() + 1];
copy(command.begin(), command.end(), com);
com[command.size()] = 0;
if (!CreateProcessW(exepath.c_str(), com, 0, 0, TRUE, CREATE_NEW_PROCESS_GROUP, 0, 0, &startupInfo, &processInfo))
return -1;
//sleep for 1 min, letting server start up
this_thread::sleep_for(chrono::minutes(1));
//command to stop server
string stopCmd = "stopn";
DWORD stopCmdByteSize = stopCmd.size() * sizeof(char);
if (!WriteFile(child_stdin_wr, stopCmd.c_str(), stopCmdByteSize, 0, 0))
return -1;
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
CloseHandle(child_stdin_wr);

要重现这一点,您的计算机需要运行 Windows 7,并且与应用程序位于同一文件夹中必须是Minecraft 服务器.jar文件(撰写本文时的版本 1.15.2(,您可以从他们的网站获取该文件。此外,服务器可能需要先进行一些设置,通过双击.jar文件首次运行它,创建所有需要的服务器文件,您必须打开"eula.txt"并通过将eula=false更改为eula=true来接受 EULA。那么服务器应该可以运行了。

如前所述,我没有编写服务器.jar文件,因此不知道java服务器程序的完整行为。

发现错误!问题解决了!

啊,经过一番剧烈思考并再次阅读文档以验证代码是否正确,我找到了罪魁祸首。

在调用WriteFile()函数时,我忘了给它一个指向 DWORD 的指针,以便它可以更新函数写入的字节数。

所以下面的代码:

if (!WriteFile(child_stdin_wr, stopCmd.c_str(), stopCmdByteSize, 0, 0))
return -1;

需要更改为:

DWORD bytesWritten = 0;
if (!WriteFile(child_stdin_wr, stopCmd.c_str(), stopCmdByteSize, &bytesWritten, 0))
return -1;

所以我想这是一种未定义的行为,Windows 10可以处理,但Windows 7不能,导致程序崩溃。由于函数调用中的一个小错误,写这篇冗长的文章有点尴尬,但伙计们,你有它!感谢那些给小费的人!:)

使用 RCON 可能会有更好的运气,RCON 是 Java 版服务器中内置的协议,用于远程管理具有简单 TCP 数据包格式的服务器,而不是尝试直接将命令写入服务器的标准输入。

有关数据包格式的说明,请参阅wiki.vg在RCON上的页面。