問題現象:
進程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)