dup重定向匿名管道父进程子进程的一些坑包含execvp调用ffmepg

来源:互联网 发布:iphone检测软件 编辑:程序博客网 时间:2024/06/05 21:01

dup重定向匿名管道父进程子进程的一些坑包含execvp调用ffmepg

本文说明再用dup做重定向的时候遇到的一些坑做一些总结。

1:FFMPEG的所有输出信息,都为错误输出流,用STDOUT_FILENO是捕获不到任何消息,必须用STDERR_FILENO,这里是个大坑;

2:子进程pid == 0 这一段代码走完返回后还会将主进程调用本函数之后的代码走一遍;

3:循环sleep要刷新fflush(stdout);才能在标准输出中输出到管道否则失败;

4:传入execvp的第二个参数argv类型为,char * execargv[LVSM_DEFAULT_STRING_LEN];当把前面的各个参数写入后,必须这样写execargv[pos] = NULL;否则失败,不能sprintf(execargv[pos],"%s",(char*)(0));或者,sprintf(execargv[pos],"%d",0);

5:代码中有匿名管道改成非阻塞的,否则read会卡住不返回。


下面是具体的代码对比看下:

//main.cpp

#include <unistd.h>  #include <stdio.h>  #include <sys/wait.h>  #include <sys/prctl.h>#include <signal.h>#include <fcntl.h>#include <string.h>#include <memory.h>#include<stdlib.h>int child_processing_transcode(int pipe_id[2],int * pchild_pid, char *execpathname,char * execargv[]){int ret = 0;int pid = 0;                            //创建子进程的pidpid = fork();                           //第一次返回就是子进程的pid*pchild_pid = pid;                      //拷贝子进程的pidif(pid< 0){  printf("error fork\n");*pchild_pid = -1;return -1;}  else if(pid == 0)                       //子进程负责写  {  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);  //Linux下让父进程结束后,子进程自动结束close(pipe_id[0]);                  //关闭匿名管道读close(STDOUT_FILENO);               //关闭标准输出close(STDERR_FILENO);               //关闭标准错误输出dup2(pipe_id[1], STDOUT_FILENO);    //将标准输出的输出重定向到匿名管道写中STDIN_FILENO == 0,STDOUT_FILENO == 1,STDERR_FILENO == 2;dup2(pipe_id[1], STDERR_FILENO);    //FFMPEG的所有输出信息,都为错误输出流,用STDOUT_FILENO是捕获不到任何消息,必须用STDERR_FILENO,这里是个大坑;//char *argv[] = {(char *)"ls",(char *)"-l",(char *)"/etc",(char *)0}; //execvp("ls",argv);//printf ("Hello\n");//printf ("123\n");//printf ("ooppqq\n");//执行外挂的ffmpegexecvp(execpathname,execargv);//这有个大坑,子进程pid == 0 这一段代码走完返回后还会将主进程调用本函数之后的代码走一遍。//循环sleep要刷新fflush(stdout);才能在标准输出中输出到管道否则失败.exit(0);               }  else                                    //父进程负责读  {  int father_pid = getpid();printf("father_pid ;%d\n",father_pid);printf("*pchild_pid : %d\n",*pchild_pid); close(pipe_id[1]);                  //关闭匿名管道的写}return ret;}int main(){int ret = 0;int npipe_id[2] = {0};                 //匿名管道,读npipe_id[0],写npipe_id[1]  int nchild_pid = 0;                    //子进程pidint nreadlen = 0;                      //管道中读取的内存长度char sreadbuf[10240] = {0};            //管道中读取的内存if(pipe(npipe_id) < 0)  {printf("error pipe\n");return 0;}//将读取fd设置成无阻塞int flag = fcntl(npipe_id[0],F_GETFL,0);flag |= O_NONBLOCK;if(fcntl(npipe_id[0],F_SETFL,flag) < 0){   perror("error fcntl(npipe_id[0],F_SETFL,flag)");   return 0;}//如果文件存在删除文件remove("out.flv");//转码 //ffmpeg -i 22.flv -acodec copy -vcodec h264 -s 352x288  -f flv out.flv//char execpathname[] = {"ffmpeg"};//char * execargv[] ={(char *)"ffmpeg",//(char *)"-i",(char *)"22.flv",//(char *)"-acodec", (char *)"copy", //(char *)"-vcodec", (char *)"h264", //(char *)"-s", (char *)"352x288"  ,(char *)"-f" ,(char *)"flv", //(char *)"out.flv",0};//遮标char execpathname[] = {"cover_standard"};char * execargv[] ={(char *)"cover_standard",0};ret = child_processing_transcode(npipe_id,&nchild_pid,execpathname,execargv);printf("nchild_pid : %d\n",nchild_pid);usleep(1000* 1000);//第一次调用waitpid时:此时尚未有子进程,所以waitpid出错,返回-1;//第二次调用waitpid时:此时有子进程,但子进程尚未结束,由于waitpid设置为非阻塞的,所以waitpid返回0;//第三次调用waitpid时:此时有子进程,所以waitpid返回子进程id;int stat = 0;int wpid = waitpid(nchild_pid, &stat, WNOHANG);   //pid=-1 等待任何子进程,相当于 wait()。 //设置成WNOHANG非阻塞父进程状态printf("first-pchild_pid: %d\n", wpid);  for (;;){nreadlen = read(npipe_id[0],sreadbuf,10240); if (nreadlen > 0){printf( "*********************************[nreadlen] : [%d] %s\n",nreadlen,sreadbuf); }memset(sreadbuf,0,10240);usleep(1000 * 1000);wpid = waitpid(-1, &stat, WNOHANG);   //pid=-1 等待任何子进程,相当于 wait()。 //设置成WNOHANG非阻塞父进程状态printf("second-pchild_pid: %d\n", wpid); //printf("getpid : %d\n",getpid());}//如果子进程执行完关闭close( npipe_id[0] );  close( npipe_id[1] ); //杀死子进程kill(nchild_pid, SIGKILL);    return 1;}



//cover_standard.cpp

#include <stdio.h>#include <unistd.h> int main(){int ret = 0;for (int i = 0; i <100; i++){printf("*****************cover_standard i : %d\n",i);usleep(1000*1000);//循环sleep要刷新fflush(stdout);才能在标准输出中输出到管道否则失败.fflush(stdout);}return 1;}

如有错误请指正:

交流请加QQ群:62054820
QQ:379969650.



原创粉丝点击