• linux c redirect 重定向


    用execvp实现时,运行adb,如果adb 服务没有启动,会启动adb服务,启动adb服务时,pipe返回的管道在读的时候堵塞了。

    查看了popen的源码,发现popen是用sh -c来执行的,避免了这个问题

    不知道sh -c做了些什么操作,使得popen可以避免这个问题

    代码如下:

     1 #ifndef __RG_REDIRECT_H
     2 #define __RG_REDIRECT_H
     3 
     4 
     5 //#ifdef _LINUX        //for linux version
     6 
     7 #include <string>
     8 
     9 #ifdef _LINUX
    10 #include <signal.h>
    11 #endif
    12 
    13 #define WAIT_FOREVER 0
    14 
    15 typedef void (*pReDirectCallBack)(const char* strOutput, bool bOver);
    16 
    17 class CRGReDirect
    18 {
    19 public:
    20     CRGReDirect();
    21     ~CRGReDirect();
    22 
    23 public:
    24     //同步方式运行ADB命令,会阻塞。命令结果保存在strResult里面返回
    25     //strCmd是需要执行的ADB命令。例如:adb_path devices
    26     int RunCmdSync(std::string& strResult, const std::string& strCmd);
    27     int RunCmdSync(std::string& strResult, const char *szCmd);
    28 
    29 
    30     //nTimeOut单位是秒
    31     int RunCmdWithTimeOut(std::string& strResult, const std::string& strCmd, int nTimeOut = WAIT_FOREVER);
    32     int RunCmdWithTimeOut(std::string& strResult, const char *szCmd, int nTimeOut = WAIT_FOREVER);
    33 
    34     //异步方式执行ADB命令,不会阻塞,直接返回线程的pid(失败返回-1)
    35     //strCmd是需要执行的ADB命令。例如:adb_path devices
    36     //ADB运行完成之后主动条用CallBack函数pFunc
    37     //成功返回非零,失败返回-1
    38     int RunCmdAsync(pReDirectCallBack pFunc, const std::string&strCmd);
    39     int RunCmdAsync(pReDirectCallBack pFunc, const char *szCmd);
    40 //    const char*    GetCmdResultString(void) const { return m_strResult.c_str(); }
    41 
    42 protected:
    43     int RunCmd(pReDirectCallBack pFunc = NULL);
    44 
    45     void CancelCommand();
    46 
    47 #ifdef _WIN32
    48     HANDLE            m_hTimer;
    49     HANDLE            m_hTimerQueue;
    50     HANDLE            m_hChildProcess;
    51 
    52     HANDLE            m_hCmdThread;
    53     static DWORD WINAPI RunProcess(void *arg);
    54     static VOID CALLBACK HandleTimeOut( PVOID lpParameter, BOOLEAN TimerOrWaitFired);
    55 #else
    56     int SetTimer(int nSeconds, int nTimerID);
    57     int KillTimer(timer_t nTimerID);
    58 
    59     timer_t                m_timer_id;
    60     pthread_t            m_thread_id;
    61     static void*        RunProcess(void* arg);
    62     static void            HandleTimeOut(sigval_t v);
    63 
    64     pid_t                *m_childpid;    /* ptr to array allocated at run-time */
    65     int                    m_maxfd;    /* from our open_max(), {Prog openmax} */
    66     FILE*                m_hChildProcess;
    67 
    68     int open_max(void);
    69     FILE * rgpopen(const char *cmdstring, const char *type);    //模拟popen实现的版本
    70     int rgpkill(FILE* fp);                                        //根据文件指针关掉相应的进程
    71     int rgpclose(FILE *fp);                                        //关闭文件指针
    72 #endif
    73 
    74 private:
    75     std::string            m_strResult;
    76     std::string            m_strCmd;
    77     pReDirectCallBack    m_adbCB;
    78     volatile bool        m_bAbort;
    79 };
    80 
    81 //#endif
    82 
    83 #endif
    #ifndef _WIN32
        #include <unistd.h>
        #include <signal.h>    
        #include <time.h>    
        #include <pthread.h>    // Compile and link with -pthread.
        #include <cstring>
        #include <cstdlib>
        #include <sys/wait.h>
        #include <sys/time.h>
        #include <sys/resource.h>
        #include <errno.h>
    #else
    #include <Windows.h>
    #endif
    
    #include "RGReDirect.h"
    #include <cassert>
    #include <cstdio>
    
    #define RG_TIMER_ID    51
    

    std::string Trim(const std::string& strIn)
    {
      std::string strMatch = " ";
      size_t i = strIn.find_first_not_of(strMatch);
      size_t j = strIn.find_last_not_of(strMatch);

    
    

      if (i != std::string::npos)
        return strIn.substr(i, j-i+1);

    
    

      return "";
    }

    
    CRGReDirect::CRGReDirect()
    : m_adbCB(NULL)
    #ifdef _WIN32
    , m_hChildProcess(NULL)
    , m_hCmdThread(NULL)
    , m_hTimer(NULL)
    , m_hTimerQueue(NULL)
    #else
    , m_thread_id(0)
    , m_timer_id(0)
    , m_childpid(NULL)
    , m_maxfd(0)
    , m_hChildProcess(NULL)
    #endif
    , m_bAbort(false)
    {
    }
    
    CRGReDirect::~CRGReDirect()
    {
    #ifdef _WIN32
        if (m_hCmdThread)
        {
            WaitForSingleObject(m_hCmdThread, INFINITE);
            CloseHandle(m_hCmdThread);
        }
        if (m_hTimer) DeleteTimerQueueTimer(m_hTimerQueue, m_hTimer, NULL);
        if (m_hTimerQueue) DeleteTimerQueue(m_hTimerQueue);
        
    #else
        if (m_thread_id) pthread_join(m_thread_id, NULL);
        if(m_timer_id) timer_delete(m_timer_id);
        if(m_childpid) free(m_childpid);
    #endif
    }
    
    int CRGReDirect::RunCmd(pReDirectCallBack pFunc /* = NULL */)
    {
        m_bAbort = false;
        m_strResult.clear();
    
    #ifdef _WIN32
        std::string strTmpCmd = m_strCmd;    
        HANDLE hChildStdoutRd, hChildStdoutWr, hStdout;
        SECURITY_ATTRIBUTES saAttr; 
    
        // Set the bInheritHandle flag so pipe handles are inherited. 
        saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
        saAttr.bInheritHandle = TRUE; 
        saAttr.lpSecurityDescriptor = NULL; 
    
        // Get the handle to the current STDOUT. 
        hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
    
        // Create a pipe for the child process's STDOUT. 
        if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) 
            return -1; 
    
        // Ensure the read handle to the pipe for STDOUT is not inherited.
        SetHandleInformation( hChildStdoutRd, HANDLE_FLAG_INHERIT, 0);
    
        char *szCmdline = new char[strTmpCmd.size() + 1];
        memset(szCmdline, 0, strTmpCmd.size() + 1);
        strcpy(szCmdline, strTmpCmd.c_str());
    
        PROCESS_INFORMATION piProcInfo; 
        STARTUPINFO siStartInfo;
    
        // Set up members of the PROCESS_INFORMATION structure. 
        ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
    
        // Set up members of the STARTUPINFO structure. 
        ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
        siStartInfo.cb = sizeof(STARTUPINFO); 
        siStartInfo.hStdError = hChildStdoutWr;
        siStartInfo.hStdOutput = hChildStdoutWr;
        siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
    
        // Create the child process. 
        BOOL bFuncRetn = CreateProcess(NULL, 
            szCmdline,     // command line 
            NULL,          // process security attributes 
            NULL,          // primary thread security attributes 
            TRUE,          // handles are inherited 
            CREATE_NO_WINDOW,             // creation flags 
            NULL,          // use parent's environment 
            NULL,          // use parent's current directory 
            &siStartInfo,  // STARTUPINFO pointer 
            &piProcInfo);  // receives PROCESS_INFORMATION 
    
        if (bFuncRetn == 0) 
        {
            delete [] szCmdline;
            return -1;
        }
        else 
        {
            m_hChildProcess = piProcInfo.hProcess;
            CloseHandle(piProcInfo.hThread);
    
            const int BUFSIZE = 4096;
            DWORD dwRead; 
            char chBuf[BUFSIZE] = {0}; 
    
            // Close the write end of the pipe before reading from the 
            // read end of the pipe. 
            if (!CloseHandle(hChildStdoutWr))
            {
                delete [] szCmdline;
                return -1;
            }
    
            // Read output from the child process
            while (m_bAbort == false) 
            { 
                if( !ReadFile( hChildStdoutRd, chBuf, BUFSIZE, &dwRead, 
                    NULL) || dwRead == 0) break; 
                chBuf[dwRead] = '';
                if(pFunc) pFunc(chBuf, false);
                else m_strResult += chBuf;
            } 
    
            CloseHandle(hChildStdoutRd);
    
            if(m_bAbort == false)    //非终止进程,则自然关闭
            {
                CloseHandle(m_hChildProcess);
                m_hChildProcess = NULL;
            }
        
            if(pFunc) pFunc("", true);
    
            delete [] szCmdline;
            return 0;
        }
    
    #else
    
        char    line[1024] = {0};
        std::string strTmpCmd = m_strCmd + " 2>&1";    //重定向stderr至stdout
    
        if((m_hChildProcess = rgpopen(strTmpCmd.c_str(), "r")) == NULL)
        {
            fprintf(stderr, "rgpopen error
    ");
            return -1;
        }
    
        while(m_bAbort == false)
        {
            if(fgets(line, 1024, m_hChildProcess) == NULL)
                break;
            if(pFunc) pFunc(line, false);
            else m_strResult += line;
        }
    
        if(pFunc) pFunc("", true);
    
        if (m_bAbort == false)    //非终止进程,则自然关闭
        {
            rgpclose(m_hChildProcess);
            m_hChildProcess = NULL;
        }
    
        return 0;
    
    #endif
    }
    
    int CRGReDirect::RunCmdSync(std::string& strResult, const std::string& strCmd)
    {
        return RunCmdSync(strResult, strCmd.c_str());
    }
    
    int CRGReDirect::RunCmdSync(std::string& strResult, const char *szCmd)
    {
        m_strCmd = szCmd;
        m_adbCB = NULL;
    
        int nRet = RunCmd(m_adbCB);
    
        strResult = m_strResult;
    
        return nRet;
    }
    
    int CRGReDirect::RunCmdAsync(pReDirectCallBack pFunc, const std::string&strCmd)
    {
        return RunCmdAsync(pFunc, strCmd.c_str());
    }
    
    int CRGReDirect::RunCmdAsync(pReDirectCallBack pFunc, const char *szCmd)
    {
        assert(pFunc);
    
        m_adbCB = pFunc;
        m_strCmd = szCmd;
    
    #ifdef _WIN32
        DWORD dwThread;
        HANDLE hThread = CreateThread(NULL, 0, RunProcess, this, 0, &dwThread);
        if (hThread)
        {
            m_hCmdThread = hThread;
            return 0;
        }
        else
        {
            return -1;
        }
    #else
        pthread_t pid;
    
        if (pthread_create(&pid, NULL, RunProcess, this) == 0)
        {
            m_thread_id = pid;
            return 0;
        }
        else
        {
            return -1;
        }
    #endif
    }
    
    int CRGReDirect::RunCmdWithTimeOut(std::string& strResult, const std::string& strCmd, int nTimeOut)
    {
        return RunCmdWithTimeOut(strResult, strCmd.c_str(), nTimeOut);
    }
    
    int CRGReDirect::RunCmdWithTimeOut(std::string& strResult, const char* szCmd, int nTimeOut)
    {
        if(nTimeOut == WAIT_FOREVER)
        {
            return RunCmdSync(strResult, szCmd);
        }
    
        m_adbCB = NULL;
        m_strCmd = szCmd;
    
    #ifdef _WIN32
        DWORD dwThread;
        HANDLE hThread = CreateThread(NULL, 0, RunProcess, this, 0, &dwThread);
        if (hThread)
        {
            m_hCmdThread = hThread;
            m_hTimerQueue = CreateTimerQueue();
            CreateTimerQueueTimer(&m_hTimer, m_hTimerQueue, HandleTimeOut, this, nTimeOut * 1000, 0, 0);
    
            WaitForSingleObject(m_hCmdThread, INFINITE);
            CloseHandle(m_hCmdThread);
            m_hCmdThread = NULL;
    
            DeleteTimerQueueTimer(m_hTimerQueue, m_hTimer, NULL);
            DeleteTimerQueue(m_hTimerQueue);
            m_hTimer = m_hTimerQueue = NULL;
    
            strResult = m_strResult;
    
            LOG("%s
    ", strResult);
    
            return 0;
        }
        else
        {
            return -1;
        }
    #else
        pthread_t pid;
    
        if (pthread_create(&pid, NULL, RunProcess, this) == 0)
        {
            m_thread_id = pid;
    
            SetTimer(nTimeOut, RG_TIMER_ID);
    
            pthread_join(m_thread_id, NULL);
            m_thread_id = 0;
    
            KillTimer(m_timer_id);
            m_timer_id = 0;
            strResult = m_strResult;
    
            return 0;
        }
        else
        {
            return -1;
        }
    #endif
    }
    
    #ifdef _WIN32
    void CRGReDirect::HandleTimeOut(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
    #else
    void CRGReDirect::HandleTimeOut(sigval_t v)
    #endif
    {
    #ifdef _WIN32
        CRGReDirect* pThis = (CRGReDirect*)lpParameter;
    #else
        CRGReDirect* pThis = (CRGReDirect*)(v.sival_ptr);
    #endif
        if (pThis)
        {
            printf("cancel command on timeout
    ");
            pThis->CancelCommand();
        }
    
    #ifdef _DEBUG
        printf("TimeOut on exit.
    ");
    #endif
    }
    
    void CRGReDirect::CancelCommand()
    {
        m_bAbort = true;
    
    #ifdef _WIN32
        if (m_hChildProcess)    //进程未退出,强行终止
        {
            TerminateProcess(m_hChildProcess, 1);
            CloseHandle(m_hChildProcess);
            m_hChildProcess = NULL;
        }
    #else
        if (m_hChildProcess)
        {
            rgpkill(m_hChildProcess);
            m_hChildProcess = NULL;
        }
    #endif
    }
    
    #ifdef _WIN32
    DWORD WINAPI CRGReDirect::RunProcess(void* arg)
    #else
    void* CRGReDirect::RunProcess(void* arg)
    #endif
    {
        CRGReDirect* pThis = (CRGReDirect *)arg;
        assert(pThis);
    
        pThis->RunCmd(pThis->m_adbCB);
    
    #ifdef _WIN32
        return 0;
    #else
        return (void *)0;
    #endif
    }
    
    #ifndef _WIN32
    int CRGReDirect::SetTimer(int nSeconds, int nTimerID)
    {
        timer_t tid;
        struct sigevent se;
    
        memset(&se, 0, sizeof(se));
        se.sigev_notify = SIGEV_THREAD;
        se.sigev_notify_function = HandleTimeOut;
        se.sigev_value.sival_ptr = this;
    
        if(timer_create(CLOCK_REALTIME, &se, &tid) < 0)
        {
    #ifdef _DEBUG
            perror("timer_create:");
    #endif
            return -1;
        }
    
        struct itimerspec ts, ots;
        ts.it_value.tv_sec = nSeconds;
        ts.it_value.tv_nsec = 0;
        ts.it_interval.tv_sec = 0;
        ts.it_interval.tv_nsec = 0;
    
        if(timer_settime(tid, 0, &ts, &ots) < 0)
        {
    #ifdef _DEBUG
            perror("timer_settime:");
    #endif
            return -1;
        }
    
        m_timer_id = tid;
    
        return 0;
    }
    
    int CRGReDirect::KillTimer(timer_t nTimerID)
    {
        return timer_delete(nTimerID);
    }
    
    #ifdef _ARM
    #define SHELL "/system/bin/sh"
    #else
    #define    SHELL "/bin/sh"
    #endif
    
    int CRGReDirect::open_max()
    {
        struct rlimit rl;
        if(getrlimit(RLIMIT_NOFILE, &rl) == 0)
            return rl.rlim_max;
    
        return 256;    //default
    }
    
    FILE* CRGReDirect::rgpopen(const char *cmdstring, const char *type)
    {
        int        i, pfd[2];
        pid_t    pid;
        FILE    *fp;
    
        /* only allow "r" or "w" */
        if ((type[0] != 'r' && type[0] != 'w') || type[1] != 0) {
            errno = EINVAL;
            return(NULL);
        }
    
        if (m_childpid == NULL) {        /* first time through */
            /* allocate zeroed out array for child pids */
            m_maxfd = open_max();
            if ( (m_childpid = (pid_t *)calloc(m_maxfd, sizeof(pid_t))) == NULL)
                return(NULL);
        }
    
        if (pipe(pfd) < 0)
            return(NULL);    /* errno set by pipe() */
    
        if ( (pid = fork()) < 0)
            return(NULL);    /* errno set by fork() */
        else if (pid == 0) {                            /* child */
            if (*type == 'r') {
                close(pfd[0]);
                if (pfd[1] != STDOUT_FILENO) {
                    dup2(pfd[1], STDOUT_FILENO);
                    close(pfd[1]);
                }
            } else {
                close(pfd[1]);
                if (pfd[0] != STDIN_FILENO) {
                    dup2(pfd[0], STDIN_FILENO);
                    close(pfd[0]);
                }
            }
            /* close all descriptors in childpid[] */
            for (i = 0; i < m_maxfd; i++)
                if (m_childpid[ i ] > 0)
                    close(i);
    
            execl(SHELL, "sh", "-c", cmdstring, (char *) 0);
            _exit(127);
        }
        /* parent */
        if (*type == 'r') {
            close(pfd[1]);
            if ( (fp = fdopen(pfd[0], type)) == NULL)
                return(NULL);
        } else {
            close(pfd[0]);
            if ( (fp = fdopen(pfd[1], type)) == NULL)
                return(NULL);
        }
        m_childpid[fileno(fp)] = pid;    /* remember child pid for this fd */
        return(fp);
    }
    
    int CRGReDirect::rgpkill(FILE* fp)
    {
        int        fd, stat;
        pid_t    pid;
    
        if (m_childpid == NULL)
            return(-1);        /* rgpopen() has never been called */
    
        fd = fileno(fp);
        if ( (pid = m_childpid[fd]) == 0)
            return(-1);        /* fp wasn't opened by rgpopen() */
    
    
        m_childpid[fd] = 0;
        fclose(fp);
    
        return kill(pid, SIGKILL);
    }
    
    int CRGReDirect::rgpclose(FILE *fp)
    {
        int        fd, stat;
        pid_t    pid;
    
        if (m_childpid == NULL)
            return(-1);        /* rgpopen() has never been called */
    
        fd = fileno(fp);
        if ( (pid = m_childpid[fd]) == 0)
            return(-1);        /* fp wasn't opened by rgpopen() */
    
        m_childpid[fd] = 0;
        if (fclose(fp) == EOF)
            return(-1);
    
        while (waitpid(pid, &stat, 0) < 0)
            if (errno != EINTR)
                return(-1);    /* error other than EINTR from waitpid() */
    
        return(stat);    /* return child's termination status */
    }
    
    #endif
  • 相关阅读:
    Logstash利用GeoIP库显示地图以及通过useragent显示浏览器(
    remote tomcat monitor---jmc--jvisualvm
    python AI(numpy,matplotlib)
    rpm package.http://rpmfind.net/
    cpuspeed和irqbalance服务器的两大性能杀手
    什么叫CallBack函数,怎么用回调函数?
    发送微博消息
    curl抓取信息
    JavaScript键盘事件全面控制代码
    js实现网页收藏功能,动态添加删除网址
  • 原文地址:https://www.cnblogs.com/jojodru/p/3975598.html
Copyright © 2020-2023  润新知