windows TCP侦听端口在进程死亡后依旧占用的问题

最近在开发一个业务模块的在线升级时,在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版权协议,转载请附上原文出处链接和本声明。