Linux下进程间通信
以下内容仅作为个人记录的参考,但也欢迎读者前来指正。
现在linux下使用较多的进程间通信方式主要有以下几种: 1.管道及有名管道(named pipe)。管道用于有亲缘关系进程间通信,有名管道没有亲缘关系限制。 2.信号(signal):信号是在软件层面对终端机制的一种模拟 3.消息队列(messagae queue):克服前面的信息量有限的缺点,具有权限限制的功能 4.共享内存(shared memory):多个进程可以同时访问同一块内存空间,依靠某种同步机制,如互斥锁和信号量。 5.信号量(semaphore):主要作为进程之间以及同一进程的不同线程之间的同步和互斥手段 6.套接字(socket)
1.管道:
创建管道时,它会创建两个文件描述符fds[0]/fds[1],分别固定为读/写。
#include<unistd.h> int pipe(int fd[2]); 成功:返回0 失败:返回-1
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<unistd.h> 4 5 int main() 6 { 7 int pipefd[2]; 8 char buff[] = "hello"; 9 int len = strlen(buff); 10 char* data; 11 data = (char*)malloc(len+1); 12 if(pipe(pipefd)<0) 13 { 14 printf("create pipe error.\n"); 15 exit(1); 16 } 17 int pid; 18 pid = fork(); 19 if(pid==0) 20 { 21 close(pipefd[1]); 22 sleep(3); 23 int readLen = read(pipefd[0],data,(len+1)); 24 if(readLen>0) 25 { 26 printf("child recv %d bytes,and data is %s\n",readLen,data); 27 exit(0); 28 } 29 30 } 31 else if(pid>0) 32 { 33 close(pipefd[0]); 34 sleep(1); 35 int writeLen = write(pipefd[1],buff,len); 36 printf("writeLen = %d\n",writeLen); 37 if(writeLen>0) 38 { 39 printf("parent write %d bytes,and data is %s.\n",writeLen,buff); 40 waitpid(pid,NULL,0); 41 exit(0); 42 } 43 } 44 return 0; 45 }
标准流管道:
使用popen(const char* command,const char* type); 类似于shell执行command一样。 type可以是"r",该命令产生输出 "w",该命令产生输入 成功:返回文件流指针 失败:返回-1 pclose(fp);关闭上面产生的文件流
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<unistd.h> 4 #include<fcntl.h> 5 #define BUFSIZE 1024 6 int main() 7 { 8 FILE* fp; 9 char* cmd = "ps -ef"; 10 char buf[BUFSIZE]; 11 12 if((fp = popen(cmd,"r"))==NULL) 13 { 14 printf("popen error.\n"); 15 exit(1); 16 } 17 18 while((fgets(buf,BUFSIZE,fp))!=NULL) 19 { 20 printf("%s",buf); 21 } 22 pclose(fp); 23 exit(0); 24 }
输出还不少啊。
FIFO:
有名管道:
使用mkfifo()函数,类似于open()
#include<sys/types.h> #include<sys/state.h> int mkfifo(const char* filename,mode_t mode); mode:O_RDONLY/O_WRONLY/O_RDWR/O_NONBLOCK/O_CREAT/O_EXCL 成功返回0,失败返回-1 出错信息: EACCESS/EEXIST/ENAMETOOLONG/ENOENT/ENOSPC/ENOTDIR/EROFS
fifo_read.c
1 #include<sys/types.h> 2 #include<sys/stat.h> 3 #include<errno.h> 4 #include<fcntl.h> 5 #include<stdio.h> 6 #include<stdlib.h> 7 #include<limits.h> 8 9 #define MYFIFO "/tmp/myfifo" 10 #define MAX_BUFFER_SIZE PIPE_BUF 11 12 int main() 13 { 14 char buf[MAX_BUFFER_SIZE]; 15 int fd; 16 int nread; 17 18 if(access(MYFIFO,F_OK)==-1) 19 { 20 if((mkfifo(MYFIFO,0666)<0)&&(errno!=EEXIST)) 21 { 22 printf("cannot create fifo file\n"); 23 exit(1); 24 } 25 } 26 27 fd = open(MYFIFO,O_RDONLY); 28 if(fd==-1) 29 { 30 printf("open fifo file error"); 31 exit(1); 32 } 33 34 while(1) 35 { 36 memset(buf,0,sizeof(buf)); 37 if((nread = read(fd,buf,MAX_BUFFER_SIZE))>0) 38 { 39 printf("read '%s' from fifo\n",buf); 40 } 41 } 42 close(fd); 43 exit(0); 44 }
fifo_write.c
1 #include<sys/types.h> 2 #include<sys/stat.h> 3 #include<errno.h> 4 #include<fcntl.h> 5 #include<stdio.h> 6 #include<stdlib.h> 7 #include<limits.h> 8 9 #define MYFIFO "/tmp/myfifo" 10 #define MAX_BUFFER_SIZE PIPE_BUF 11 12 int main(int argc,char* argv[]) 13 { 14 int fd; 15 char buf[MAX_BUFFER_SIZE]; 16 int nwrite; 17 18 if(argc<=1) 19 { 20 printf("Usage: ./fifo_write string\n"); 21 exit(1); 22 } 23 sscanf(argv[1],"%s",buf); 24 25 fd = open(MYFIFO,O_WRONLY); 26 if(fd==-1) 27 { 28 printf("open fifo file error\n"); 29 exit(1); 30 } 31 if((nwrite=write(fd,buf,MAX_BUFFER_SIZE))>0) 32 { 33 printf("write '%s' to fifo\n",buf); 34 } 35 close(fd); 36 exit(0); 37 }
先启动读程序
再启动写程序
信号与信号量暂且跳过,直接看一下共享内存。
共享内存:
分为两个步骤。
(1):创建共享内存 shmget(),从内存获取一段共享内存区域
(2):映射共享内存 把创建的共享内存映射到具体的进程空间,使用函数shmat()
撤销映射函数 shmdt()
shmget()
#include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> int shmget(key_t key,int size,int shmflg); key为共享内存的键值,特殊值IPC_PRIVATE,用于创建当前进程的私有共享内存 返回-1为出错,否则为共享内存标识符
shmat()
#include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> char* shmat(int shmid,const void* shmaddr,int shmflg); shmflg: SHM_RDONLY 只读,0为可读可写 -1:出错,否则返回被映射的段地址
shmdt()
#include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> int shmdt(const void* shmaddr); 成功返回0,出错返回-1
shmem.c
1 #include<sys/types.h> 2 #include<sys/ipc.h> 3 #include<sys/shm.h> 4 #include<stdio.h> 5 #include<stdlib.h> 6 #include<string.h> 7 8 #define BUFFER_SIZE 2048 9 10 int main() 11 { 12 pid_t pid; 13 int shmid; 14 char* shm_addr; 15 char flag[] = "write"; 16 char buff[BUFFER_SIZE]; 17 18 if((shmid = shmget(IPC_PRIVATE,BUFFER_SIZE,0666))<0) 19 { 20 perror("shmget"); 21 exit(1); 22 } 23 else 24 { 25 printf("create shared-memory: %d\n",shmid); 26 } 27 system("ipcs -m"); 28 29 pid = fork(); 30 if(pid==-1) 31 { 32 perror("fork"); 33 exit(1); 34 } 35 else if(pid ==0) 36 { 37 if((shm_addr = shmat(shmid,0,0))==(void*)-1) 38 { 39 perror("child: shmat"); 40 exit(1); 41 } 42 else 43 { 44 printf("child attach shared-memory: %p\n",shm_addr); 45 } 46 system("ipcs -m"); 47 48 while(strncmp(shm_addr,flag,strlen(flag))) 49 { 50 printf("child: wait enable data...\n"); 51 sleep(5); 52 } 53 54 strcpy(buff,shm_addr + strlen(flag)); 55 printf("child: shared-memory :%s\n",buff); 56 57 if(shmdt(shm_addr)<0) 58 { 59 perror("shmdt"); 60 exit(1); 61 } 62 else 63 { 64 printf("child: deattach shared-memory\n"); 65 } 66 system("ipcs -m"); 67 68 if(shmctl(shmid,IPC_RMID,NULL)==-1) 69 { 70 perror("child: shmctl(IPC_RMID)\n"); 71 exit(1); 72 } 73 else 74 { 75 printf("delete shared-memory\n"); 76 } 77 system("ipcs -m"); 78 } 79 else 80 { 81 if((shm_addr = shmat(shmid,0,0))==(void*)-1) 82 { 83 perror("parent: shmat"); 84 exit(1); 85 } 86 else 87 { 88 printf("parent: attach shared-memory: %p\n",shm_addr); 89 } 90 sleep(1); 91 printf("\ninput some string:\n"); 92 fgets(buff,BUFFER_SIZE,stdin); 93 strncpy(shm_addr+strlen(flag),buff,strlen(buff)); 94 strncpy(shm_addr,flag,strlen(flag)); 95 96 if((shmdt(shm_addr))<0) 97 { 98 perror("parent: shmdt"); 99 exit(1); 100 } 101 else 102 { 103 printf("parent: deattach shared-memory\n"); 104 } 105 system("ipcs -m"); 106 waitpid(pid,NULL,0); 107 printf("finished\n"); 108 } 109 }
运行结果:
[root@iZmcbceic4fsvzZ file]# gcc shmem.c [root@iZmcbceic4fsvzZ file]# ./a.out create shared-memory: 98307 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 0 root 666 2048 0 0x00000000 32769 root 666 2048 0 0x00000000 65538 root 666 2048 0 0x00000000 98307 root 666 2048 0 parent: attach shared-memory: 0x7f399d89e000 child attach shared-memory: 0x7f399d89e000 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 0 root 666 2048 0 0x00000000 32769 root 666 2048 0 0x00000000 65538 root 666 2048 0 0x00000000 98307 root 666 2048 2 child: wait enable data... input some string: hello world parent: deattach shared-memory ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 0 root 666 2048 0 0x00000000 32769 root 666 2048 0 0x00000000 65538 root 666 2048 0 0x00000000 98307 root 666 2048 1 child: shared-memory :hello world child: deattach shared-memory ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 0 root 666 2048 0 0x00000000 32769 root 666 2048 0 0x00000000 65538 root 666 2048 0 0x00000000 98307 root 666 2048 0 delete shared-memory ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 0 root 666 2048 0 0x00000000 32769 root 666 2048 0 0x00000000 65538 root 666 2048 0 finished [root@iZmcbceic4fsvzZ file]#
消息队列:
msgget():创建和打开消息队列
#include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> int msgget(key_t key,int msgflg); key和共享内存类似,IPC_PRIVATE 出错返回-1,否则返回队列ID
msgsnd():发送消息
#include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> int msgsnd(int msqid,const void* msgp,size_t msgsz,int msgflg) msqid:消息队列的队列ID msgp:指向消息结构的指针。 为一个结构体 struct msgbuf{ long mtype;//消息类型 char msgtext[1];//消息正文 }; msgsz:消息正文的字节数 msgflg: IPC_NOWAIT 若消息无法立刻发送,直接返回 0:阻塞发送直到发送成功 出错返回-1,否则返回0
msgrcv():接收消息
#include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> int msgrcv(int msgid,void* msgp,size_t msgsz,long int msgtype,int msgflg); 前3个参数,和msgsnd类似。 msgtype: 0:接收消息队列中第一个消息。 >0:接收消息队列中第一个为msgtype的消息 <0:接收消息中第一个类型值不小于msgtype绝对值,且类型值最小的消息。 msgflg: MSG_ERROR:截断消息长度到不超过msgsz长度 IPC_NOWAIT:如果消息队列中没有响应类型消息可以接收,立即返回 0:阻塞接收,直到收到一条符合类型的消息 返回-1为出错,0为成功。
msgctl():控制消息队列
#include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> int msgctl(int msgid,int cmd,struct msqid_ds* buf); cmd: IPC_STAT,读取消息队列的数据结构,并储存再buf指定的地址。 IPC_SET,设置数据结构中的ipc_perm与 IPC_RMID:从系统内核中删除消息队列 出错返回-1,成功返回0
msgrcv.c
1 #include<sys/types.h> 2 #include<sys/ipc.h> 3 #include<sys/shm.h> 4 #include<stdio.h> 5 #include<stdlib.h> 6 #include<unistd.h> 7 #include<string.h> 8 #define BUFFER_SIZE 512 9 10 struct message{ 11 long msg_type; 12 char msg_text[BUFFER_SIZE]; 13 }; 14 15 int main() 16 { 17 int qid; 18 key_t key; 19 struct message msg; 20 if((key = ftok(".",'a'))==-1) 21 { 22 perror("ftok"); 23 exit(1); 24 } 25 26 if((qid = msgget(key,IPC_CREAT|0666))==-1) 27 { 28 perror("msgget"); 29 exit(1); 30 } 31 printf("open queue %d\n",qid); 32 33 do{ 34 memset(msg.msg_text,0,BUFFER_SIZE); 35 if(msgrcv(qid,(void*)&msg,BUFFER_SIZE,0,0)<0) 36 { 37 perror("msgrcv"); 38 exit(1); 39 } 40 printf("the message from process %d: %s\n",msg.msg_type,msg.msg_text); 41 } while(strncmp(msg.msg_text,"quit",4)); 42 43 if((msgctl(qid,IPC_RMID,NULL))<0) 44 { 45 perror("msgctl"); 46 exit(1); 47 } 48 exit(0); 49 }
msgsnd.c
1 #include<sys/types.h> 2 #include<sys/ipc.h> 3 #include<sys/shm.h> 4 #include<stdio.h> 5 #include<stdlib.h> 6 #include<unistd.h> 7 #include<string.h> 8 #define BUFFER_SIZE 512 9 10 struct message{ 11 long msg_type; 12 char msg_text[BUFFER_SIZE]; 13 }; 14 15 int main() 16 { 17 int qid; 18 key_t key; 19 struct message msg; 20 if((key = ftok(".",'a'))==-1) 21 { 22 perror("ftok"); 23 exit(1); 24 } 25 26 if((qid = msgget(key,IPC_CREAT|0666))==-1) 27 { 28 perror("msgget"); 29 exit(1); 30 } 31 printf("open queue %d\n",qid); 32 33 while(1) 34 { 35 printf("enter some message to the queue:\n"); 36 if((fgets(msg.msg_text,BUFFER_SIZE,stdin))==NULL) 37 { 38 puts("no message"); 39 exit(1); 40 } 41 msg.msg_type = getpid(); 42 if((msgsnd(qid,&msg,strlen(msg.msg_text),0))<0) 43 { 44 perror("message posted."); 45 exit(1); 46 } 47 if(strncmp(msg.msg_text,"quit",4)==0) 48 { 49 break; 50 } 51 } 52 exit(0); 53 }