Windows下system()函数的性能及替代方案技术问询(C++)
问题背景
以下C++代码会在应用每次收到基于WINSOCK.h的TCP握手请求时执行,通过system()调用netsh命令检测指定IP的防火墙规则是否存在:
int result = 0; CString pCommand; CString pIP; pIP.Format("1.1.1.1"); pCommand.Format("netsh advfirewall firewall show rule name=\"TestRule : %s\"",pIP.GetString()); result = system(pCommand.GetString()); if ( Result == 1 ) { printf("Firewall Rule Not Found.\n"); } else { printf("Firewall Rule Found.\n"); }
技术问题
- 能否使用ShellExecute/ShellExecuteEx复现上述代码的执行结果?
- 若可以,其性能是否优于
system()调用,还是继续使用原代码即可? - 使用CreateProcess替代
system()或ShellExecute是否更优,且能得到相同结果?
问题解答
1. 能否用ShellExecute/ShellExecuteEx复现结果?
可以,但需要额外处理才能拿到命令执行的退出码,以此复现原代码的判断逻辑:
ShellExecute/ShellExecuteEx默认不返回进程退出码,需要通过SEE_MASK_NOCLOSEPROCESS标记获取进程句柄,等待进程结束后用GetExitCodeProcess拿到退出码。- 执行控制台命令时,需指定
cmd.exe /c作为启动程序,将netsh命令作为参数传递。示例代码如下:SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) }; sei.fMask = SEE_MASK_NOCLOSEPROCESS; sei.lpVerb = _T("open"); sei.lpFile = _T("cmd.exe"); sei.lpParameters = _T("/c netsh advfirewall firewall show rule name=\"TestRule : 1.1.1.1\""); sei.nShow = SW_HIDE; // 隐藏控制台窗口 if (ShellExecuteEx(&sei)) { WaitForSingleObject(sei.hProcess, INFINITE); DWORD exitCode; GetExitCodeProcess(sei.hProcess, &exitCode); CloseHandle(sei.hProcess); // 用exitCode替代原result做规则存在性判断 if (exitCode == 1) { printf("Firewall Rule Not Found.\n"); } else { printf("Firewall Rule Found.\n"); } }
2. ShellExecute/ShellExecuteEx的性能对比
性能和system()相差不大,甚至略逊一筹。因为system()本质也是启动cmd.exe执行命令,而ShellExecute多了一层Shell解析逻辑(比如处理文件关联、快捷方式等),额外的解析步骤会带来微小的性能开销。如果只是执行控制台命令,没必要替换,继续用原代码的system()完全可行。
3. CreateProcess是否更优且能得到相同结果?
是,CreateProcess是更优的选择,原因如下:
- 性能更好:直接启动
netsh.exe,无需通过cmd.exe中转,减少了中间进程的创建开销,对于频繁触发的场景(比如每次TCP握手都执行),性能提升更明显。 - 控制更精细:可直接指定进程的启动参数、窗口状态、优先级等,还能直接获取进程句柄和退出码,无需依赖Shell的额外处理。
- 能得到完全相同的结果:只要正确构造
netsh的命令参数,就能和原代码一样判断防火墙规则是否存在。示例代码如下:STARTUPINFO si = { sizeof(STARTUPINFO) }; PROCESS_INFORMATION pi; si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; // 隐藏窗口 CString pIP = _T("1.1.1.1"); CString pArgs; pArgs.Format(_T("advfirewall firewall show rule name=\"TestRule : %s\""), pIP.GetString()); BOOL success = CreateProcess(_T("netsh.exe"), pArgs.GetBuffer(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); pArgs.ReleaseBuffer(); if (success) { WaitForSingleObject(pi.hProcess, INFINITE); DWORD exitCode; GetExitCodeProcess(pi.hProcess, &exitCode); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); if (exitCode == 1) { printf("Firewall Rule Not Found.\n"); } else { printf("Firewall Rule Found.\n"); } }
内容的提问来源于stack exchange,提问作者Azriel Elijay
相关产品推荐
相关产品推荐

