程序中解決Windows服務器下進程不存在但端口被佔用問題

程序中解決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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章