本文以一个例子来演示通过管道如何实现进程间通讯。(一个进程是自己的进程,另一个进程是自己进程创建的shell进程。)以及在实现中得到的体会。
1.管道的创建
管道的创建函数如下:
#include
int pipe(int pipefd[2]);
#define _GNU_SOURCE
#include
int pipe2(int pipefd[2], int flags);
(1).pipefd[0]:为读打开,pipefd[1]:为写打开。 pipefd[1]的输出是pipefd[0]的输入。
(2).创建失败时返回-1,成功返回0.
(3).pipe2中,当flags=0,相当于pipe。flags 有 O_NONBLOCK ,设置两个管道为非阻塞模式,flags有 O_CLOEXEC 时,设置。。。。。
2.管道的一般应用都是和fork结合起来使用。这样两个进程就能通讯。
3.fork函数:
#include <>
#include <>
pid_t fork(void);
fork函数返回值若是大于0,则表示本进程是父进程,若返回值等于0,则表示本进程是子进程。若小于0,则表示出错。
4.例子:
- #include <signal.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <dirent.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/wait.h>
- #include <sys/syscall.h>
- #include <setjmp.h>
- #define BUFFER_SIZE 4096
- #define DEBUG
- int fd1[2] = {-1,-1},fd2[2] ={-1,-1};
- bool bStartShell = false;
- void AppendLog(char *log)
- {
- }
- static void sig_pipe(int sig)
- {
- return ;
- }
- pid_t pid;
- char lineEOF[3]={0xd,0xa,0};
- bool RunCmd(char* recvBuf,int recvlen,char* sendBuf);
- bool StartShell(char* line)
- {
- if(bStartShell) return 1;
- signal(SIGPIPE,SIG_IGN);
- //创建两个管道,一个管道是为了向写,另一个是为了读取结果。
-
- if(pipe(fd1) < 0 || pipe(fd2) < 0)
- return 0;
- //以上内容父、子进程共享
- signal(SIGCHLD,SIG_IGN);
- if((pid=fork()) < 0) //创建子进程错误。
- {
- close(fd2[0]);close(fd2[1]);
- return 0;
- }
-
- else if(pid) //parent process
- {
- //AppendLog("parent process");
- signal(SIGHUP,SIG_IGN);
-
- //父进程向fd1[1]写,从fd2[0]读最后的结果。
-
- close(fd1[0]); close(fd2[1]);
- char cmd[100];
- bool bok;
- while(1)
- {
- if(fgets(cmd,100,stdin)==NULL) break;
- printf("cmd = %s\n",cmd);
- bok = RunCmd(cmd,strlen(cmd),line);
- printf("output = %s\n",line);
- }
- return 0;
- }
- else//child process
- {
- char Msg[100];
- //子进程,输入为fd1[0],输出为fd2[1],
-
- close(fd1[1]); close(fd2[0]);
-
- //定义shell的标准输入为fd1[0]
- if(fd1[0] != STDIN_FILENO)
- {
- if(dup2(fd1[0],STDIN_FILENO) != STDIN_FILENO) {
- AppendLog("dup2 fd1[0] error");
- close(fd1[0]);
- }
- }
- //定义shell的标准输出为fd2[1]
- if(fd2[1] != STDOUT_FILENO)
- {
- if(dup2(fd2[1],STDOUT_FILENO) != STDOUT_FILENO) {
- AppendLog("dup2 fd2[1] error");
- close(fd2[1]);
- }
- }
- //把stdin,stdout设置为行缓冲,每次读/写一行。
- setvbuf(stdin,NULL,_IOLBF,0);
- setvbuf(stdout,NULL,_IOLBF,0);
-
- //子进程为shell。
- if(execl("/bin/sh","sh",(char*)0) < 0) return 0;
- }
- return 1;
- }
- static jmp_buf env_alrm;
- static void sig_alrm(int signo)
- {
- //AppendLog("sig_alarm");
- longjmp(env_alrm,1);
- exit(1);
- }
- bool RunCmd(char* recvBuf,int recvLen,char* sendBuf)
- {
- if(recvBuf == 0) return 0;
- if(recvLen == 0) return 0;
- if(sendBuf == 0) return 0;
- if((fd1[1]==-1 || fd2[0]==-1) &&!bStartShell) return 1;
-
- int n;
- char line[BUFFER_SIZE];
-
- strcpy(line,(const char *)recvBuf);
- line[recvLen] = 0xa;
- printf("recv = %s\n",line);
- if((line[1]=='e' || line[1]=='E') &&
- (line[2]=='x' || line[2]=='X') &&
- (line[3]=='i' || line[3]=='I') &&
- (line[4]=='t' || line[1]=='T'))
- {
- if(write(fd1[1],line,recvLen+1)!=recvLen) return 0;
- close(fd1[1]);
- close(fd2[0]);
- fd1[1] = -1;
- fd2[0] = -1;
- bStartShell = false;
- }
- pid = fork();
-
- if(pid) //farther process ,负责向shell进程发送命令
- {
- signal(SIGHUP,SIG_IGN);
-
- AppendLog(line);
-
- int ret = write(fd1[1],line,recvLen);
-
- if(ret <0)
- {
- //AppendLog("write fd1[1] fail");
- close(fd1[1]);close(fd2[0]);
- bStartShell = false;
- write(fd1[1],line,recvLen+1);
- }
- AppendLog("write fd1[1] ok");
- if((line[1] =='c'||line[1]=='C') && line[2]=='d'||line[2]=='D')
- {
- strcpy(line,"pwd");
- line[3]=0xa;
- write(fd1[1],line,4);
- }
- AppendLog("wait read ......");
- //等待子进程结束,意味着读取命令结果成功。
- waitpid(pid,NULL,0);
- //sleep(10);
- //n = read(fd2[0],line,BUFFER_SIZE);
- //if(n < 0) {printf("read error");exit(0);}
- //else if(n==0) { AppendLog("pipe closed");exit(0);}
- //else
- // printf("%s\n",line);
- //AppendLog("waitpid over!");
-
- }
- else //子进程,负责执行结果的读取。
- {
- memset(sendBuf,0,BUFFER_SIZE);
- int flag = false;
- signal(SIGALRM,sig_alrm);
- setjmp(env_alrm);
- char Msg[200];
- do
- {
- alarm(5);
- AppendLog("......read.....");
- n = read(fd2[0],line,BUFFER_SIZE-1);
- if(n < 0) break;
- alarm(0);
- sprintf(Msg,"read n = %d",n);
- printf("%s\n",line);
- }while(n == BUFFER_SIZE-1);
- exit(0);
- }
- return 1;
- }
- int main()
- {
- bool bok ;
- char cmd[BUFFER_SIZE],line[BUFFER_SIZE];
- bok = StartShell(line);
- }
阅读(722) | 评论(0) | 转发(0) |