进程已不存在,但端口仍被占用
问题现象:
进程SA已经结束, 但其守护进程Daemon却始终无法connect SA. 在connect(port)时出错. 使用telnet 127.0.0.1 9090 也无法连接上SA的端口. 使用TcpView查看进程与端口对应关系, 发现9090端口仍被占用, 但对应的进程却是[non-existent].
原因:
经查, 该问题出现的原因, 是由于SA进程已经结束了, 但经由SA产生的某些子进程却还未结束,资源还未完全释放,导致端口仍被占用.
解决:
1. 经查, SA结束后, 其所启动的winamp, 在SA主进程Run()结束的时候, 并没有被kill掉. 结束winamp进程.
2. 修改winamp后,本以为问题会解决,但是该问题仍重现了. 再次调查,使用 Process Explorer查看进程, 发现有几个"cmd.exe"进程是由SA启动的(将鼠标放在进程上, 弹出的悬浮窗口所显示的信息可看到该cmd是由SA所启动的), 这几个"cmd.exe"进程在SA结束后,并没有被关闭.
strCmd.Format("rd %s /s /q", strWorkDirectory); ::system(strCmd);
上面代码的目的是remove directory(rd). system()函数,会默认启动cmd.exe.
为解决此问题, 需要将SA所启动的"cmd.exe"结束掉. 但是其他进程也有启动"cmd.exe", 包括系统进程. 他们所启动额"cmd.exe"不能被kill掉.
解决办法是: 遍历进程, 如果遇见"cmd.exe", 则判断它的父进程是否存在,如果存在,不作处理,如果不存在,则将该"cmd.exe" kill掉.
int ProcessStatus(UINT uPid) { HANDLE hProcessSnap; HANDLE hProcess; PROCESSENTRY32 pe32; // Take a snapshot of all processes in the system. hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); if( hProcessSnap == INVALID_HANDLE_VALUE ) { return -1; } // Set the size of the structure before using it. pe32.dwSize = sizeof( PROCESSENTRY32 ); // Retrieve information about the first process, // and exit if unsuccessful if( !Process32First( hProcessSnap, &pe32 ) ) { CloseHandle( hProcessSnap ); // clean the snapshot object return -1; } do { if(pe32.th32ProcessID == uPid) return 1; } while( Process32Next( hProcessSnap, &pe32 ) ); CloseHandle( hProcessSnap ); return 0; } void KillProcessByPid(UINT uPid) { CString strCmd; strCmd.Format("taskkill /f /pid %u", uPid); ::system(strCmd); } void KillExistentProcess() { HANDLE hProcessSnap; HANDLE hProcess; PROCESSENTRY32 pe32; // Take a snapshot of all processes in the system. hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); if( hProcessSnap == INVALID_HANDLE_VALUE ) { return; } // Set the size of the structure before using it. pe32.dwSize = sizeof( PROCESSENTRY32 ); // Retrieve information about the first process, // and exit if unsuccessful if( !Process32First( hProcessSnap, &pe32 ) ) { CloseHandle( hProcessSnap ); // clean the snapshot object return; } do { char *pImageName = pe32.szExeFile; if(strcmp("cmd.exe", pImageName) == 0) { int nStatus = ProcessStatus(pe32.th32ParentProcessID); if (nStatus == 0) { // If parent process doesn't exist KillProcessByPid(pe32.th32ProcessID); } } } while( Process32Next( hProcessSnap, &pe32 ) ); CloseHandle( hProcessSnap ); }
参考:
How do I kill a process that is dead but listening? (http://superuser.com/questions/215351/how-do-i-kill-a-process-that-is-dead-but-listening)
How do you free up a port being held open by dead process? (http://serverfault.com/questions/181015/how-do-you-free-up-a-port-being-held-open-by-dead-process/273727#273727)