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

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

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

代码如下:

 #ifndef __RG_REDIRECT_H
#define __RG_REDIRECT_H //#ifdef _LINUX //for linux version #include <string> #ifdef _LINUX
#include <signal.h>
#endif #define WAIT_FOREVER 0 typedef void (*pReDirectCallBack)(const char* strOutput, bool bOver); class CRGReDirect
{
public:
CRGReDirect();
~CRGReDirect(); public:
//同步方式运行ADB命令,会阻塞。命令结果保存在strResult里面返回
//strCmd是需要执行的ADB命令。例如:adb_path devices
int RunCmdSync(std::string& strResult, const std::string& strCmd);
int RunCmdSync(std::string& strResult, const char *szCmd); //nTimeOut单位是秒
int RunCmdWithTimeOut(std::string& strResult, const std::string& strCmd, int nTimeOut = WAIT_FOREVER);
int RunCmdWithTimeOut(std::string& strResult, const char *szCmd, int nTimeOut = WAIT_FOREVER); //异步方式执行ADB命令,不会阻塞,直接返回线程的pid(失败返回-1)
//strCmd是需要执行的ADB命令。例如:adb_path devices
//ADB运行完成之后主动条用CallBack函数pFunc
//成功返回非零,失败返回-1
int RunCmdAsync(pReDirectCallBack pFunc, const std::string&strCmd);
int RunCmdAsync(pReDirectCallBack pFunc, const char *szCmd);
// const char* GetCmdResultString(void) const { return m_strResult.c_str(); } protected:
int RunCmd(pReDirectCallBack pFunc = NULL); void CancelCommand(); #ifdef _WIN32
HANDLE m_hTimer;
HANDLE m_hTimerQueue;
HANDLE m_hChildProcess; HANDLE m_hCmdThread;
static DWORD WINAPI RunProcess(void *arg);
static VOID CALLBACK HandleTimeOut( PVOID lpParameter, BOOLEAN TimerOrWaitFired);
#else
int SetTimer(int nSeconds, int nTimerID);
int KillTimer(timer_t nTimerID); timer_t m_timer_id;
pthread_t m_thread_id;
static void* RunProcess(void* arg);
static void HandleTimeOut(sigval_t v); pid_t *m_childpid; /* ptr to array allocated at run-time */
int m_maxfd; /* from our open_max(), {Prog openmax} */
FILE* m_hChildProcess; int open_max(void);
FILE * rgpopen(const char *cmdstring, const char *type); //模拟popen实现的版本
int rgpkill(FILE* fp); //根据文件指针关掉相应的进程
int rgpclose(FILE *fp); //关闭文件指针
#endif private:
std::string m_strResult;
std::string m_strCmd;
pReDirectCallBack m_adbCB;
volatile bool m_bAbort;
}; //#endif #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 = " \t\r\n";
  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()
, m_timer_id()
, m_childpid(NULL)
, m_maxfd()
, 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, ))
return -; // Ensure the read handle to the pipe for STDOUT is not inherited.
SetHandleInformation( hChildStdoutRd, HANDLE_FLAG_INHERIT, ); char *szCmdline = new char[strTmpCmd.size() + ];
memset(szCmdline, , strTmpCmd.size() + );
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 == )
{
delete [] szCmdline;
return -;
}
else
{
m_hChildProcess = piProcInfo.hProcess;
CloseHandle(piProcInfo.hThread); const int BUFSIZE = ;
DWORD dwRead;
char chBuf[BUFSIZE] = {}; // Close the write end of the pipe before reading from the
// read end of the pipe.
if (!CloseHandle(hChildStdoutWr))
{
delete [] szCmdline;
return -;
} // Read output from the child process
while (m_bAbort == false)
{
if( !ReadFile( hChildStdoutRd, chBuf, BUFSIZE, &dwRead,
NULL) || dwRead == ) break;
chBuf[dwRead] = '\0';
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 ;
} #else char line[] = {};
std::string strTmpCmd = m_strCmd + " 2>&1"; //重定向stderr至stdout if((m_hChildProcess = rgpopen(strTmpCmd.c_str(), "r")) == NULL)
{
fprintf(stderr, "rgpopen error\n");
return -;
} while(m_bAbort == false)
{
if(fgets(line, , 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 ; #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, , RunProcess, this, , &dwThread);
if (hThread)
{
m_hCmdThread = hThread;
return ;
}
else
{
return -;
}
#else
pthread_t pid; if (pthread_create(&pid, NULL, RunProcess, this) == )
{
m_thread_id = pid;
return ;
}
else
{
return -;
}
#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, , RunProcess, this, , &dwThread);
if (hThread)
{
m_hCmdThread = hThread;
m_hTimerQueue = CreateTimerQueue();
CreateTimerQueueTimer(&m_hTimer, m_hTimerQueue, HandleTimeOut, this, nTimeOut * , , ); 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\n", strResult); return ;
}
else
{
return -;
}
#else
pthread_t pid; if (pthread_create(&pid, NULL, RunProcess, this) == )
{
m_thread_id = pid; SetTimer(nTimeOut, RG_TIMER_ID); pthread_join(m_thread_id, NULL);
m_thread_id = ; KillTimer(m_timer_id);
m_timer_id = ;
strResult = m_strResult; return ;
}
else
{
return -;
}
#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\n");
pThis->CancelCommand();
} #ifdef _DEBUG
printf("TimeOut on exit.\n");
#endif
} void CRGReDirect::CancelCommand()
{
m_bAbort = true; #ifdef _WIN32
if (m_hChildProcess) //进程未退出,强行终止
{
TerminateProcess(m_hChildProcess, );
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 ;
#else
return (void *);
#endif
} #ifndef _WIN32
int CRGReDirect::SetTimer(int nSeconds, int nTimerID)
{
timer_t tid;
struct sigevent se; memset(&se, , 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) < )
{
#ifdef _DEBUG
perror("timer_create:");
#endif
return -;
} struct itimerspec ts, ots;
ts.it_value.tv_sec = nSeconds;
ts.it_value.tv_nsec = ;
ts.it_interval.tv_sec = ;
ts.it_interval.tv_nsec = ; if(timer_settime(tid, , &ts, &ots) < )
{
#ifdef _DEBUG
perror("timer_settime:");
#endif
return -;
} m_timer_id = tid; return ;
} 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) == )
return rl.rlim_max; return ; //default
} FILE* CRGReDirect::rgpopen(const char *cmdstring, const char *type)
{
int i, pfd[];
pid_t pid;
FILE *fp; /* only allow "r" or "w" */
if ((type[] != 'r' && type[] != 'w') || type[] != ) {
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) < )
return(NULL); /* errno set by pipe() */ if ( (pid = fork()) < )
return(NULL); /* errno set by fork() */
else if (pid == ) { /* child */
if (*type == 'r') {
close(pfd[]);
if (pfd[] != STDOUT_FILENO) {
dup2(pfd[], STDOUT_FILENO);
close(pfd[]);
}
} else {
close(pfd[]);
if (pfd[] != STDIN_FILENO) {
dup2(pfd[], STDIN_FILENO);
close(pfd[]);
}
}
/* close all descriptors in childpid[] */
for (i = ; i < m_maxfd; i++)
if (m_childpid[ i ] > )
close(i); execl(SHELL, "sh", "-c", cmdstring, (char *) );
_exit();
}
/* parent */
if (*type == 'r') {
close(pfd[]);
if ( (fp = fdopen(pfd[], type)) == NULL)
return(NULL);
} else {
close(pfd[]);
if ( (fp = fdopen(pfd[], 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(-); /* rgpopen() has never been called */ fd = fileno(fp);
if ( (pid = m_childpid[fd]) == )
return(-); /* fp wasn't opened by rgpopen() */ m_childpid[fd] = ;
fclose(fp); return kill(pid, SIGKILL);
} int CRGReDirect::rgpclose(FILE *fp)
{
int fd, stat;
pid_t pid; if (m_childpid == NULL)
return(-); /* rgpopen() has never been called */ fd = fileno(fp);
if ( (pid = m_childpid[fd]) == )
return(-); /* fp wasn't opened by rgpopen() */ m_childpid[fd] = ;
if (fclose(fp) == EOF)
return(-); while (waitpid(pid, &stat, ) < )
if (errno != EINTR)
return(-); /* error other than EINTR from waitpid() */ return(stat); /* return child's termination status */
} #endif

linux c redirect 重定向的更多相关文章

  1. Linux管道及重定向

    Linux管道及重定向 对shell有一定了解的人都知道,管道和重定向是 Linux 中非常实用的 IPC 机制.在shell中,我们通常使用符合'|'来表示管道,符号'>'和'<'表示重 ...

  2. Linux I/O 重定向详解及应用实例

    Linux I/O 重定向详解及应用实例 简解 > 输出 < 输入 >> 追加 & [> | < | >>]之前:输入输出; ls /dev & ...

  3. Linux下Shell重定向

    1. 标准输入,标准输出与标准错误输出 Linux下系统打开3个文件,标准输入,标准输出,标准错误输出. 标准输入:从键盘输入数据,即从键盘读入数据. 标准输出:把数据输出到终端上. 标准错误输出:把 ...

  4. Linux I/O重定向

    所谓I/O重定向简单来说就是一个过程,这个过程捕捉一个文件,或者命令,程序,脚本,甚至脚本中的代码块的输出,然后把捕捉到的输出,作为输入 发送给另外一个文件,命令,程序,或者脚本.谈到I/O重定向,就 ...

  5. Linux入门-7 Linux管道、重定向以及文本处理

    Linux管道.重定向以及文本处理 1 Linux多命令协作:管道及重定向 管道和重定向 2 Linux命令行文本处理工具 文件浏览 基于关键字搜索-grep 基于列处理文本-cut 文本统计-wc ...

  6. (转)linux exec与重定向

    原文:http://xstarcd.github.io/wiki/shell/exec_redirect.html linux exec与重定向 exec和source都属于bash内部命令(buil ...

  7. Linux标准输入、重定向与参数传递

    Linux标准输入.重定向与参数传递 按惯例,每当运行一个新程序时,所有shell都为其打开3个文件描述符,即标准输入.标准输出以及标准错误.如果不做特殊处理,例如就像简单的命令ls,则这三个描述符都 ...

  8. linux中nginx重定向方法总结

    linux中nginx 301重定向跳转方法总结 第一种情况:访问aaaaaaa站定向到bbbbbbbbbbb站 复制代码代码如下: server { server_naaaaaaame www.aa ...

  9. 【Linux】数据流重定向

    数据流重定向(redirect)就是将某个命令执行后应该要出现在屏幕上的数据,给它传输到其他的地方,例如文件或设备(打印机之类的).这玩意在Linux的命令行模式下很重要,尤其是想要将某些数据存储下来 ...

随机推荐

  1. Substrings - HDU 1238(最大共同子串)

    题目大意:给你N个串,求出来他们的最大公共子串的长度(子串反过来也算他们的子串).   分析:很久以前就做过这道题,当时是用的strstr做的,不过相同的都是枚举了子串......还是很暴力,希望下次 ...

  2. appium点击屏幕(手势)

    在android测试过程中,会遇到要点击一下屏幕的需求. 在appium旧版本使用下面代码点击android屏幕,没有报错.Map tap = new HashMap(); tap.put(" ...

  3. Delphi图像处理 -- RGB与HSL转换

    阅读提示:     <Delphi图像处理>系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM.     <C++图像处理>系列以代码清晰,可读性为主,全部使用C ...

  4. c# mongo 返回指定的列

    var query= db.GetCollection<Merchant>("merchant").Find(Query<Merchant>.EQ(m =& ...

  5. golang中channel的超时处理

    并发中超时处理是必不可少的,golang没有提供直接的超时处理机制,但可以利用select机制来解决超时问题. func timeoutFunc() { //首先,实现并执行一个匿名的超时等待函数 t ...

  6. [转] TCP数据包重组实现分析

    PS: 这个实现对于某些特定情况未必是最佳实现,可以用数组来代替队列来实现 参照TCP/IP详解第二卷24~29章,详细论述了TCP协议的实现,大概总结一下TCP如何向应用层保证数据包的正确性.可靠性 ...

  7. iOS平台基于ffmpeg的视频直播技术揭秘

    现在非常流行直播,相信很多人都跟我一样十分好奇这个技术是如何实现的,正好最近在做一个ffmpeg的项目,发现这个工具很容易就可以做直播,下面来给大家分享下技术要点: 首先你得编译出ffmpeg运行所需 ...

  8. Mysql 中和同to_char 一样用法的函数

    STR_TO_DATE() $sql = " SELECT "; $sql .= " m_img,m_content,STR_TO_DATE(m_time,\" ...

  9. HTML5 离线缓存详解(转)

    离线缓存是html5新特性之一,简单理解就是第一次加载后将数据缓存,在没有清除缓存前提下,下一次没有网络也可以加载,用在静态数据的网页或游戏比较好用.当然,Html5新的特性都不是所有浏览器都能支持的 ...

  10. c-函数指针(求奇数偶数的和)

    #include <stdio.h> /* 编写一个函数,输入 n 为偶数时,调用函数求 1/2+1/4+...+1/n,当输入 n 为奇数时,调用函数1/1+1/3+...+1/n(利用 ...