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.
");
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
",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
",writeLen);
37                 if(writeLen>0)
38                 {
39                         printf("parent write %d bytes,and data is %s.
",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.
");
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
");
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
",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
");
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
");
29                 exit(1);
30         }
31         if((nwrite=write(fd,buf,MAX_BUFFER_SIZE))>0)
32         {
33                 printf("write '%s' to fifo
",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
",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
",shm_addr);
 45                 }
 46                 system("ipcs -m");
 47 
 48                 while(strncmp(shm_addr,flag,strlen(flag)))
 49                 {
 50                         printf("child: wait enable data...
");
 51                         sleep(5);
 52                 }
 53 
 54                 strcpy(buff,shm_addr + strlen(flag));
 55                 printf("child: shared-memory :%s
",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
");
 65                 }
 66                 system("ipcs -m");
 67 
 68                 if(shmctl(shmid,IPC_RMID,NULL)==-1)
 69                 {
 70                         perror("child: shmctl(IPC_RMID)
");
 71                         exit(1);
 72                 }
 73                 else
 74                 {
 75                         printf("delete shared-memory
");
 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
",shm_addr);
 89                 }
 90                 sleep(1);
 91                 printf("
input some string:
");
 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
");
104                 }
105                 system("ipcs -m");
106                 waitpid(pid,NULL,0);
107                 printf("finished
");
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
",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
",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
",qid);
32 
33         while(1)
34         {
35                 printf("enter some message to the queue:
");
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 }

原文地址:https://www.cnblogs.com/dayq/p/15362679.html