进程已不存在,但端口仍被占用

问题现象:

进程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)

 

posted @ 2013-02-04 11:22  金石开  阅读(10834)  评论(0编辑  收藏  举报