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


    问题现象:

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

  • 相关阅读:
    Docker部署Tomcat
    Docker部署MySQL
    kettle 共享数据库连接(解决每次都需要创建数据库连接问题)
    Kettle8.2的安装与使用
    Kettle 使用JS脚本 增加UUID输出列
    kettle使用(mysql导入MongoDB)
    Eclipse从Git上下载代码
    Eclipse中使用git
    在windows下安装git中文版客户端并连接gitlab
    eclipse中git的安装、配置和使用
  • 原文地址:https://www.cnblogs.com/zhcncn/p/2891489.html
Copyright © 2020-2023  润新知