From b08ea0fcc7f4006beb087541d2f91addb835cb51 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Mon, 8 Jun 2020 14:56:17 +0800 Subject: [PATCH] =?UTF-8?q?windows=E4=B8=8B=E5=AD=90=E8=BF=9B=E7=A8=8B?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=97=A5=E5=BF=97=E9=87=8D=E5=AE=9A=E5=90=91?= =?UTF-8?q?=E3=80=81=E7=AD=89=E5=BE=85=E5=AD=90=E8=BF=9B=E7=A8=8B=E6=8E=A8?= =?UTF-8?q?=E5=87=BA=E3=80=81=E8=8E=B7=E5=8F=96=E5=AD=90=E8=BF=9B=E7=A8=8B?= =?UTF-8?q?=E9=80=80=E5=87=BA=E7=A0=81=E7=AD=89=E7=89=B9=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/FFmpegSource.cpp | 11 ++-- server/Process.cpp | 123 +++++++++++++++++++++++++++++++++------- 2 files changed, 108 insertions(+), 26 deletions(-) diff --git a/server/FFmpegSource.cpp b/server/FFmpegSource.cpp index 95f079c7..0ed137a2 100644 --- a/server/FFmpegSource.cpp +++ b/server/FFmpegSource.cpp @@ -24,19 +24,16 @@ const string kSnap = FFmpeg_FIELD"snap"; onceToken token([]() { #ifdef _WIN32 - string ffmpeg_bin = System::execute("where ffmpeg"); - //windows下先关闭FFmpeg日志(目前不支持日志重定向) - mINI::Instance()[kCmd] = "%s -re -i %s -loglevel quiet -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s"; - mINI::Instance()[kSnap] = "%s -i %s -loglevel quiet -y -f mjpeg -t 0.001 %s"; + string ffmpeg_bin = trim(System::execute("where ffmpeg")); #else - string ffmpeg_bin = System::execute("which ffmpeg"); - mINI::Instance()[kCmd] = "%s -re -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s"; - mINI::Instance()[kSnap] = "%s -i %s -y -f mjpeg -t 0.001 %s"; + string ffmpeg_bin = trim(System::execute("which ffmpeg")); #endif //默认ffmpeg命令路径为环境变量中路径 mINI::Instance()[kBin] = ffmpeg_bin.empty() ? "ffmpeg" : ffmpeg_bin; //ffmpeg日志保存路径 mINI::Instance()[kLog] = "./ffmpeg/ffmpeg.log"; + mINI::Instance()[kCmd] = "%s -re -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s"; + mINI::Instance()[kSnap] = "%s -i %s -y -f mjpeg -t 0.001 %s"; }); } diff --git a/server/Process.cpp b/server/Process.cpp index 40030444..f877bdfc 100644 --- a/server/Process.cpp +++ b/server/Process.cpp @@ -16,6 +16,7 @@ #else //#include #include +#include #endif #include @@ -31,23 +32,44 @@ using namespace toolkit; void Process::run(const string &cmd, const string &log_file_tmp) { kill(2000); #ifdef _WIN32 - STARTUPINFO si; - PROCESS_INFORMATION pi; - ZeroMemory(&si, sizeof(si)); //结构体初始化; - ZeroMemory(&pi, sizeof(pi)); + STARTUPINFO si = {0}; + PROCESS_INFORMATION pi = {0}; + string log_file; + if (log_file_tmp.empty()) { + //未指定子进程日志文件时,重定向至/dev/null + log_file = "NUL"; + } + else { + log_file = StrPrinter << log_file_tmp << "." << getCurrentMillisecond(); + } + + //重定向shell日志至文件 + auto fp = File::create_file(log_file.data(), "ab"); + if (!fp) { + fprintf(stderr, "open log file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno)); + } else { + auto log_fd = (HANDLE)(_get_osfhandle(fileno(fp))); + // dup to stdout and stderr. + si.wShowWindow = SW_HIDE; + // STARTF_USESHOWWINDOW:The wShowWindow member contains additional information. + // STARTF_USESTDHANDLES:The hStdInput, hStdOutput, and hStdError members contain additional information. + si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + si.hStdError = log_fd; + si.hStdOutput = log_fd; + } LPTSTR lpDir = const_cast(cmd.data()); - - if (CreateProcess(NULL, lpDir, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)){ + if (CreateProcess(NULL, lpDir, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)){ //下面两行关闭句柄,解除本进程和新进程的关系,不然有可能 不小心调用TerminateProcess函数关掉子进程 CloseHandle(pi.hProcess); CloseHandle(pi.hThread); - _pid = pi.dwProcessId; + fprintf(fp, "\r\n\r\n#### pid=%d,cmd=%s #####\r\n\r\n", _pid, cmd.data()); InfoL << "start child proces " << _pid; } else { - WarnL << "start child proces fail: " << GetLastError(); + WarnL << "start child proces fail: " << get_uv_errmsg(); } + fclose(fp); #else _pid = fork(); if (_pid < 0) { @@ -125,16 +147,42 @@ static bool s_wait(pid_t pid,int *exit_code_ptr,bool block) { if (pid <= 0) { return false; } - int status = 0; #ifdef _WIN32 HANDLE hProcess = NULL; - hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程 - if (hProcess == NULL) { + hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); //打开目标进程 + if (!hProcess) { + WarnL << "OpenProcess failed:" << get_uv_errmsg(); + return false; + } + + DWORD code = 0; + if (block) { + //一直等待 + code = WaitForSingleObject(hProcess, INFINITE); + } else { + code = WaitForSingleObject(hProcess, 0); + } + + if(code == WAIT_FAILED || code == WAIT_OBJECT_0){ + //子进程已经退出了,获取子进程退出代码 + DWORD exitCode = 0; + if(GetExitCodeProcess(hProcess, &exitCode) && exit_code_ptr){ + *exit_code_ptr = exitCode; + } + CloseHandle(hProcess); return false; } CloseHandle(hProcess); + if(code == WAIT_TIMEOUT){ + //子进程还在线 + return true; + } + //不太可能运行到此处 + WarnL << "WaitForSingleObject ret:" << code; + return false; #else + int status = 0; pid_t p = waitpid(pid, &status, block ? 0 : WNOHANG); int exit_code = (status & 0xFF00) >> 8; if (exit_code_ptr) { @@ -148,11 +196,42 @@ static bool s_wait(pid_t pid,int *exit_code_ptr,bool block) { InfoL << "process terminated, pid=" << pid << ", exit code=" << exit_code; return false; } -#endif // _WIN32 - return true; +#endif // _WIN32 } +#ifdef _WIN32 +// Inspired from http://stackoverflow.com/a/15281070/1529139 +// and http://stackoverflow.com/q/40059902/1529139 +bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent){ + bool success = false; + DWORD thisConsoleId = GetCurrentProcessId(); + // Leave current console if it exists + // (otherwise AttachConsole will return ERROR_ACCESS_DENIED) + bool consoleDetached = (FreeConsole() != FALSE); + + if (AttachConsole(dwProcessId) != FALSE){ + // Add a fake Ctrl-C handler for avoid instant kill is this console + // WARNING: do not revert it or current program will be also killed + SetConsoleCtrlHandler(nullptr, true); + success = (GenerateConsoleCtrlEvent(dwCtrlEvent, 0) != FALSE); + FreeConsole(); + } + + if (consoleDetached){ + // Create a new console if previous was deleted by OS + if (AttachConsole(thisConsoleId) == FALSE){ + int errorCode = GetLastError(); + if (errorCode == 31){ + // 31=ERROR_GEN_FAILURE + AllocConsole(); + } + } + } + return success; +} +#endif // _WIN32 + static void s_kill(pid_t pid,int max_delay,bool force){ if (pid <= 0) { //pid无效 @@ -161,13 +240,20 @@ static void s_kill(pid_t pid,int max_delay,bool force){ #ifdef _WIN32 HANDLE hProcess = NULL; hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程 - if (hProcess == NULL) { - WarnL << "\nOpen Process fAiled: " << GetLastError(); + if (!hProcess) { + //子进程可能已经推出了 return; } - DWORD ret = TerminateProcess(hProcess, 0); //结束目标进程 - if (ret == 0) { - WarnL << GetLastError; + if(force){ + //强制关闭 + DWORD ret = TerminateProcess(hProcess, 0); //结束目标进程 + CloseHandle(hProcess); + if (ret == 0) { + WarnL << "TerminateProcess " << pid << " failed:" << get_uv_errmsg(); + } + }else{ + //非强制关闭,发生Ctr+C信号 + signalCtrl(pid, CTRL_C_EVENT); } #else if (::kill(pid, force ? SIGKILL : SIGTERM) == -1) { @@ -177,7 +263,6 @@ static void s_kill(pid_t pid,int max_delay,bool force){ } #endif // _WIN32 - if(force){ //发送SIGKILL信号后,阻塞等待退出 s_wait(pid, NULL, true);