您的位置:首页 > 其它

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

2017-08-18 15:00 274 查看
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; //创建子进程的pid

pid = fork(); //第一次返回就是子进程的pid
*pchild_pid = pid; //拷贝子进程的pid

if(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");

//执行外挂的ffmpeg
execvp(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; //子进程pid
int 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.

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: