使用fork(), pipe() 實現linux的popen, pclose功能

爲什麼要自己實現一個popen\pclose函數功能呢?因爲,有時系統popen打開的文件,有時會出現pclose時一直阻塞着,導致整個應用程序無法正常結束,此時使用我們自己實現的popen,則可以獲得進程ID,然後通過kill該進程ID來結束popen開啓的文件;

FILE*    Popen(const char* commandstr, const char* mode)
{
    pid_t pid;
    int pfd[2];
    int nRet = pipe(pfd); // 創建管道(pfd[0] 讀管道,pfd[1] 寫管道)
    if (-1 == nRet)
    {
        printf("error: pipe() call fails\n");
        WriteLog(LOG_INFO, "[LogFileMonitor] error: pipe() call fails");
        return NULL;
    }

    pid = fork();
    if (pid < 0)
    {
        printf("error: fork() call fails.\n");
        WriteLog(LOG_INFO, "[LogFileMonitor] error: fork() call fails");
        return NULL;
    }
    else if (pid == 0)
    {
        printf("I am child process, pid = %d\n", getpid());
        WriteLog(LOG_INFO, "[LogFileMonitor] I am child process, pid = %d", getpid());
        // 負責寫數據 --- 寫管道
        close(pfd[0]);
        if (pfd[1] != STDOUT_FILENO)
        {
            dup2(pfd[1], STDOUT_FILENO); // 標準輸出 指向 管道的輸出文件描述符
            close(pfd[1]);
        }

        execl(SHELL, "sh", "-c", commandstr, (char *)0);
        _exit(127);
    }
    else
    {
        printf("I am parent process, pid = %d\n", getpid());
        WriteLog(LOG_INFO, "[LogFileMonitor] I am parent process, pid = %d", getpid());
        // 負責讀數據 --- 讀管道
        close(pfd[1]);
        FILE *fp = NULL;
        if ((fp = fdopen(pfd[0], "r")) == NULL)
        {
            return NULL;
        }
        return fp;
    }
}

int     Pclose(FILE* fp)
{
    //使用非阻塞io
    int flags = 0;
    int nfd = fileno(fp);
    if (flags = fcntl(nfd, F_GETFL, 0) < 0)
    {
        LOG(LERROR) << "fcntl() get failed";
        WriteLog(LOG_ERROR, "[LogFileMonitor] fcntl() get failed");
        return false;
    }

    flags &= ~O_NONBLOCK;
    if (fcntl(nfd, F_SETFL, flags) < 0)
    {
        LOG(LERROR) << "fcntl() set noblock failed";
        WriteLog(LOG_ERROR, "[LogFileMonitor] set noblock failed");
        return false;
    }

    if (fclose(fp) == EOF)
    {
        return -1;
    }

    WriteLog(LOG_INFO, "[LogFileMonitor] Pclose() _exit(128)");
    _exit(128);
    return 0;
}

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