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