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

标签 java c++ crash windows-7

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

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

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

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

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

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

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

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

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

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

Console application crashes, Windows "Program has stopped working." dialog is not shown on picture.

编辑:

好的,所以我创建了一个最小的可重现示例。这是所有需要的代码(用于 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 = "stop\n\0";
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 server.jar 文件 (撰写本文时版本 1.15.2)您可以从 their website. 获得此外,服务器可能需要先进行一些设置,第一次通过双击 .jar 文件运行它会创建所有需要的服务器文件,您必须打开“eula.txt”并通过更改 eula=false 来接受 EULA至eula=true .然后服务器应该很好去。

如前所述,我没有编写 server.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不能处理的一种未定义行为,导致程序崩溃。由于函数调用中的一个小错误,写这篇冗长的帖子有点尴尬,但是有伙计们,你有它!感谢那些提供提示的人! :)

关于java - 父进程被运行 java jar 的子 cmd.exe 进程意外杀死 - WINDOWS 7 问题 - C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62206546/

相关文章:

ios - 应用程序在iOS 8上崩溃并显示崩溃日志,该日志中的内容

iphone - 无法找到我的应用程序遇到的最后一个错误的任何答案……[内部挑战;)]

java - 多线程声明期间静态变量初始化

Java(或 Cpp)在某处阻塞

c++ - clock_t 在 Linux 上不起作用?

c++ - delete[] 的这种行为是否符合预期 - 仅删除前两个元素?

java - 从类 libgdx 中绘图

java - 如何获取List子类的REAL类型参数?

Java android java.lang.RuntimeException : Parcelable encountered IOException writing serializable object

ios - NSOperationQueue 导致 Crashlytics 崩溃(QOS : UNSPECIFIED)