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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhuweigangzwg/article/details/77369828

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.



猜你喜欢

转载自blog.csdn.net/zhuweigangzwg/article/details/77369828