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

问题描述 投票:0回答:2

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

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

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

但是子进程退出后,控制台应用程序意外崩溃,并且Windows“程序已停止运行。”对话框出现。 奇怪的是,我已经在运行Windows 10的编程笔记本电脑上测试了该应用程序,并且该应用程序在发行和调试模式下都没有出现任何问题。我的服务器计算机运行的是Windows 7,因此似乎是Windows 7的问题。

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

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

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

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

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

[如果有人对可能出现的问题有任何提示或想法,我将耳熟能详。谢谢!

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=true接受EULA。然后服务器就可以了。

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

java c++ crash windows-7
2个回答
0
投票

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

关于包格式的说明,请参阅wiki.vg's page on RCON


0
投票

发现错误!问题解决了!

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

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无法处理,这是一种不确定的行为,导致程序崩溃。.由于函数调用中的一个小错误,写这篇冗长的帖子有点尴尬,但是那里有你们!感谢那些给小费的人! :)

© www.soinside.com 2019 - 2024. All rights reserved.