程序中解決Windows服務器下進程不存在但端口被佔用問題
問題現象:
1、使用命令netstat -ano | findstr 端口
查看端口占用進程,會得到端口占用進程的PID號,但通過PID號在任務管理器中查不到該進程,且使用命令taskkill /f /pid PID號
時報錯沒有找到進程;
2、使用Process Explorer工具搜索PID號會發現進程中存在一cmd.exe子進程;
3、若此時在任務管理器中或cmd命令中殺死該cmd.exe進程,會發現原佔用端口被釋放。
問題原因:
程序停止時調用了system()
函數,而此函數會啓動cmd.exe程序執行系統命令,在某些異常情況(也可能系統本身問題)下,會出現原程序已被停止釋放,但cmd子進程遲遲未被回收,導致原程序佔用端口未被釋放。
程序修改方法:
可以通過父子進程的關係進行優化解決,雖然系統其它進程也會調用cmd.exe進程,但正常情況下它們父子關係是存在的。在如上問題中,cmd.exe進程的父進程已不存在,故可以將其看做是異常泄漏進程。那麼,我們在啓動程序服務前只需讓程序遍歷目前服務器中所有的進程,找到不存在父子關係的cmd.exe進程,將其先行殺死,這樣既可避免因異常cmd進程佔用程序端口導致程序無法啓動的問題。
#include <Tlhelp32.h>
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)
{
char strCmd[50]={0};
_snprintf(strCmd, 49, "taskkill /f /t /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 );
}
void StartSvr()
{
KillExistentProcess();
…
…
…
}
參考:https://www.cnblogs.com/zhcncn/archive/2013/02/04/2891489.html