爲什麼要自己實現一個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;
}