Linux系统编程学习笔记(十)进程间通信IPC 1
进程间通信IPC:
我们以前介绍过进程控制原语,看到怎么创建多个进程。但是进程之间交互信息的方式只介绍了通过
fork或者exec继承父进程的打开文件或者通过文件系统。
经典的进程通信方式有:管道、FIFOs,消息队列,信号灯和共享内存。
1、管道:
管道是Unix系统IPC最古老的形式,PIPE有以下限制:
1)是半双工的,一些系统提供了全双工的管道,但是为了可移植性,我们最好不要作此假设。
2)管道只能在有共同祖先的进程之间。一般一个进程创建一个管道,然后进程调用fork,
然后管道在父进程和子进程之间使用。
FIFO摆脱了第二个限制,Unix domain socket和具名STREAMS-based管道可以摆脱这两者的限制。
尽管有以上限制,半双工的管道仍然是最常使用的IPC。
1)创建管道:
#include <unistd.h>int pipe(int filedes[2]);
#include <unistd.h>#include <sys/types.h>#include <stdlib.h>int main(void){int n;int fd[2];pid_t pid;char line[MAXLINE];if(pipe(fd) < 0){perror("pipe");exit(1);}if((pid = fork()) < 0){perror("fork");exit(1);}else if(pid > 0){close(fd[0]);write(fd[1],"hello,world\n",12);}else{close(fd[1]);n = read(fd[0],line,MAXLINE);write(STDOUT_FILENO,line,n);}exit(0);}#include <unistd.h>#include <sys/types.h>#include <stdlib.h>#include <sys/wait.h>#include <stdio.h>#define DEF_PAGER "/bin/more"int main(int argc,char *argv[]){int n;int fd[2];pid_t pid;char *pager, *argv0;char line[MAXLINE];FILE *fp;if(argc != 2){printf("Usage: a.out <pathname>");exit(1);}if((fp = fopen(argv[1],"r")) == NULL){perror("fopen");exit(1);}if(pipe(fd) < 0){perror("pipe");exit(1);}if((pid = fork()) < 0){perror("fork");exit(1);}else if(pid > 0){/* parent */close(fd[0]);/* close read end */while(fgets(line,MAXLINE,fp) != NULL){n = strlen(line);if(write(fd[1],line,n) != n){perror("write");exit(1);}}if(ferror(fp)){perror("fgets");exit(1);}close(fd[1]); /* close write end of the pipe for reader */if(waitpid(pid,NULL,0) < 0){perror("waitpid");exit(1);}exit(0);}else{/* child */close(fd[1]);if(fd[0] != STDIN_FILENO){if(dup2(fd[0],STDIN_FILENO) != STDIN_FILENO){perror("dup2");exit(1);}close(fd[0]);/* don't need it after dup2}/* get arguments for execl() */if((pager = getenv("PAGER")) == NULL){pager = DEF_PAGER;}if((argv0 = strrchr(pager,'/')) != NULL)argv0++;/* step past rightmost slash */elseargv0 = pager;if(execl(pager,argv0,(char *)0) < 0){perror("execl");exit(1);}}exit(1);}#include <stdio.h>FILE *popen(const char *cmdstring, const char *type);int pclose(FILE *fp);
#include <unistd.h>#include <sys/types.h>#include <stdlib.h>#include <sys/wait.h>#include <stdio.h>#define PAGER "${PAGER:-more}"int main(int argc, char *argv){char line[MAXLINE];FILE *fpin, *fpout;if(argc != 2){printf("usage: a.out <pathname>\n");exit(1);}if((fpin = fopen(argv[1],"r")) == NULL){perror("fopen");exit(1);}if((fout = popen(PAGER,"w")) = NULL){perror("popen");exit(1);}while(fgets(line,MAXLINE,fpin) != NULL){if(fputs(line,fpout) == EOF){perror("fputs");exit(1);}}if(ferror(fpin)){perror("fgets");exit(1);}if(pclose(fpout)){perror("pclose");exit(1);}exit(0);}#include <sys/stat.h>int mkfifo(const char *path, mode_t mode;);
#define FIFO_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S _IROTH)if(mkfifo("myfifo",FIFO_PERMS) == -1)perror("Failed to create myfifo");#include <errno.h>#include <fcntl.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <sys/stat.h>#include <sys/wait.h>#define BUFSIZE 256#define FIFO_PERM (S_IRUSR | S_IWUSR)int dofifochild(const char *fifoname, const char *idstring);int dofifoparent(const char *fifoname);int main(int argc,char *argv[]){pid_t childpid;if(argc != 2){fprintf(stderr,"Usage: %s pipename\n",argv[0]);return 1;}if(mkfifo(argv,FIFO_PERM) == -1){if(errno != EEXIT){fprintf(stderr,"[%ld]": failed to create name pipe %s: %s\n",(long)getpid(),argv[1],strerror(errno));return 1;}}if(childpid = fork()) == -1){perror("Failed to fork");return 1;}if(childpid == 0){return dofifochild(argv[1],"this was written by the child");}else{return dofifochild(argv[1]);}}int dofifochild(const char *fifoname, const char *idstring){char buf[BUFSIZE];int fd;int rval;ssize_t strsize;fprintf(stderr,"[%ld]:(child) about to open FIFO %s...\n",(long)getpid(),fifoname);if(fd = open(fifoname,O_WRONLY) == -1){fprintf(stderr,"[%ld]:failed to open name pipe %s for write: %s\n",(long)getpid(),fifoname,strerror(errno));return 1;}rval = snprintf(buf,BUFSIZE,"[%ld]:%s\n",(long)getpid(),idstring);if(rval < 0){fprintf(stderr,"[%ld]": failed to make the string:\n",(long)getpid());return 1;}strsize = strlen(buf)+1;fprintf(stderr,[%ld]:about to write...\n",(long)getpid());rval = write(fd,buf,strsize);if(rval != strsize){fprintf(stderr,"[%ld]:failed to write to pipe: %s\n",(long)getpid(),strerror(errno));return 1;}fprintf(stderr,"[%ld]:finishing...\n",(long)getpid());return 0;}int dofifoparent(const char *fifoname) { char buf[BUFSIZE]; int fd; int rval; fprintf(stderr, "[%ld]:(parent) about to open FIFO %s...\n", (long)getpid(), fifoname); if ((fd = open(fifoname, FIFO_MODES)) == -1) { fprintf(stderr, "[%ld]:failed to open named pipe %s for read: %s\n", (long)getpid(), fifoname, strerror(errno)); return 1; } fprintf(stderr, "[%ld]:about to read...\n", (long)getpid()); rval = read(fd, buf, BUFSIZE); if (rval == -1) { fprintf(stderr, "[%ld]:failed to read from pipe: %s\n", (long)getpid(), strerror(errno)); return 1; } fprintf(stderr, "[%ld]:read %.*s\n", (long)getpid(), rval, buf); return 0;}#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include<sys/stat.h>#define FIFOARG 1#define BLKSIZE 1024#define FIFO_PERMS (S_IRWXU | S_IWGRP | S_IWOTH)int main(int argc, char *argv[]){int requestfd;if(argc != 2){fprintf(stderr,"Usage: %s fifoname > logfile\n",argv[0]);return 1;}if((mkfifo(argv[FIFOARG],FIFO_PERMS) == -1) && (errno != EEXIST)){perror("Server failed to create FIFO");return 1;}if((requestfd = open(argv[FIFOARG],O_RDWR)) == -1){perror("Server failed to open its FIFO");return 1;}copyfile(requestfd,STDOUT_FILENO);return 1;}int copyfile(int fromfd, int tofd) { char *bp; char buf[BLKSIZE]; int bytesread, byteswritten; int totalbytes = 0; for ( ; ; ) { while (((bytesread = read(fromfd, buf, BLKSIZE)) == -1) && (errno == EINTR)) ; /* handle interruption by signal */ if (bytesread <= 0) /* real error or end-of-file on fromfd */ break; bp = buf; while (bytesread > 0) { while(((byteswritten = write(tofd, bp, bytesread)) == -1 ) && (errno == EINTR)) ; /* handle interruption by signal */ if (byteswritten <= 0) /* real error on tofd */ break; totalbytes += byteswritten; bytesread -= byteswritten; bp += byteswritten; } if (byteswritten == -1) /* real error on tofd */ break; } return totalbytes;}#include <errno.h>#include <fcntl.h>#include <limits.h>#include <stdio.h>#include <stdlib.h>#include <strings.h>#include <time.h>#include <unistd.h>#include <sys/stat.h>#define FIFOARG 1int main(int argc, char *argv[]){time_t curtime;int len;char requestbuf[PIPE_BUF];int requestfd;if(argc != 2){fprintf(stderr,"Usage %s fifoname", argv[0]);return 1;}if((requestfd = open(argv[FIFOARG],O_WRONLY)) == -1){perror("Client failed to open log fifo for writing");return 1;}curtime = time(NULL)snprintf(requestbuf,PIPE_BUF,"%d:%s",(int)getpid(),ctime(&curtime));len = strlen(requestbuf);if(write(requestfd,requestbuf,len) != len){perror("Client failed to write");return 1;}close(requestfd);return 0;}