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] = '