最近在开发一个业务模块的在线升级时,在windows平台遇到一个诡异的问题。旧的进程已经死亡了,但是通过netstat查看,死亡进程依旧占用了TCP侦听端口。
从上图可见,2776进程占用12345端口,但通过tasklist查看,进程已经消亡了。
百思不得其解,通过仔细观察升级过程,发现在升级后会有cmd.exe进程一直存在不退出。
于是便想到去查看这个cmd.exe到底在执行什么不退出。windows可以通过wmic where caption="cmd.exe" get caption,commandline /value查看一个cmd.exe的命令行参数。
可见是cmd在删除一个目录,参数是/K,那么一定是这个/K导致了cmd.exe不退出了,查看一下cmd的帮助。
可见“cmd /c”命令执行完cmd.exe会退出,"cmd /K"命令执行完cmd.exe不会退出。
代码里是通过调用system()函数来执行cmd命令的,也就是若是system("rd /s/q C:\test"),实际执行命令是 "cmd /K rd /s/q C:\test".
改为system("cmd /c rd /s/q C:\test")则命令执行完cmd.exe也会跟着消亡。
至此,还有一个问题就是为什么cmd.exe不退出,侦听端口就会被占用呢?
这就涉及到windows创建进程是否继承父进程的文件句柄了。调用system()继承了父进程的文件句柄,导致在执行的命令进程不退出的时候占用父进程的侦听端口。
通过调用CreateProcess执行windows命令,可以在函数参数中指定不继承父进程的文件句柄。
void cmdProcess( const char* strCmd)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
//隐藏掉可能出现的cmd命令窗口
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
(LPSTR)(LPCTSTR)strCmd, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return;
}
printf("%s\n", strCmd);
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
调用eg:
cmdProcess("cmd /c rd /s/q C:\test");
版权声明:本文为dongsongz原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。