IPC 基本结构

简述

IPC通信包括:共享内存,消息队列,信号灯

IPC结构

三种通信方式的函数

共享内存

shmget创建共享内存
打开或创建一个共享内存对象,共享内核在内核是什么样子的?
一块缓存,变类似于用户空间的数组或malloc函数分配的空间一样。

查看IPC对象:ipcs -m【查看共享内存】| -q【队列】| -s【信号灯】
删除IPC对象:ipcrm -m | -q | -s id【IPC的ID】

共享内存的读

共享内存可以通过memcpy写入,也可以通过键盘输入stdin

删除映射到用户的内存

利用键盘输入读取共享内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*************************************************************************
> File Name: shm_0.c
> Author: Merlynr
> Mail: lcq1013962426@gmail.com
> Created Time: 2023年02月01日 星期三 22时44分26秒
************************************************************************/

#include<stdio.h>
#include<sys/types.h>
#include<sys/shm.h>
#include<signal.h>
#include<sys/ipc.h>
#include<unistd.h>
#include<stdlib.h>

int main()
{
int shmid;
int key;
char *p;
key = ftok("./myfifo",'b');
if(key < 0)
{
printf("create key failure\n");
return -1;
}
printf("create key sucess key = %X\n",key);
shmid = shmget(key,128,IPC_CREAT | 0777);
if(shmid<0)
{
printf("create share memory failure\n");
return -2;
}
printf("create share memory sucess shmid = %X\n",shmid);
system("ipcs -m");
//create user memoey mapping
p = (char *)shmat(shmid,NULL,0);
if(p==NULL)
{
printf("shmat func failure\n");
return -3;
}

// write to memory by keymap
fgets(p,128,stdin);

// read
printf("share memory data: %s\n",p);

return 0;
}

ret

**共享内存特点**:

  1. 共享内存创建之后,一直存在于内核中,直到被删除或系统关闭:
  2. 共享内存和管道不一样,读取后,内容仍在其共享内存中。
1
2
3
4
5
6
7
8
9
10
//基于上一段代码的修改
// read
printf("share memory data: %s\n",p);

printf("second read :%s\n",p);

shmdt(p);
system("ipcs -m");
memcpy(p,"abcd",4);
return 0;

shmdt后,共享内存依旧存在但用户无法写入,说明映射到用户的内存被删除了

查看,设置,删除共享内存,shmctl

1
2
3
4
5
6
7
8
9
// 删除共享内存
shmdt(p);
// system("ipcs -m");
//memcpy(p,"abcd",4);
// printf("third read :%s\n",p);
shmctl(shmid,IPC_RMID,NULL);
printf("have delete share memory\n");
system("ipcs -m");
return 0;

ret

不同进程之间的通信

宏IPC_PRIVATE:只可以打开亲属之间的共享内存,不同进程之间的需要ftok来获取shmid。

服务端代码,进程通过kill发送SIGUSR1给客户端进程告知已写入share memory。同时接收SIGUSR2信号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*************************************************************************
> File Name: shm_0.c
> Author: Merlynr
> Mail: lcq1013962426@gmail.com
> Created Time: 2023年02月01日 星期三 22时44分26秒
************************************************************************/

#include<stdio.h>
#include<sys/types.h>
#include<string.h>
#include<sys/shm.h>
#include<signal.h>
#include<sys/ipc.h>
#include<unistd.h>
#include<stdlib.h>
struct mybuf
{
int pid;
char buf[124];
};
void myfun()
{
printf("myfun\n");
}
int main()
{
int shmid;
int key;
struct mybuf *p;
int pid;
key = ftok("./myfifo",'b');
if(key < 0)
{
printf("create key failure\n");
return -1;
}
printf("create key sucess key = %X\n",key);
shmid = shmget(key,128,IPC_CREAT | 0777);
if(shmid<0)
{
printf("create share memory failure\n");
return -2;
}
printf("create share memory sucess shmid = %X\n",shmid);
signal(SIGUSR2,myfun);

p = (struct mybuf *)shmat(shmid,NULL,0);
if(p==NULL)
{
printf("shmat func failure\n");
return -3;
}

p->pid = getpid();//write server pid to share memory
pause(); // wait client read server pid;
pid = p->pid;//read client pid;

while(1)
{
printf("parent process start write share memory!\n");
fgets(p->buf,128,stdin);
kill(pid,SIGUSR1);// client process read data
pause();//wait client process read
}
shmdt(p);
shmctl(shmid,IPC_RMID,NULL);
return 0;
}

客户端代码,进程通过kill发送SIGUSR2给服务端进程告知已读取share memory。同时接收SIGUSR1信号,进行读取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/*************************************************************************
> File Name: shm_0.c
> Author: Merlynr
> Mail: lcq1013962426@gmail.com
> Created Time: 2023年02月01日 星期三 22时44分26秒
************************************************************************/

#include<stdio.h>
#include<sys/types.h>
#include<string.h>
#include<sys/shm.h>
#include<signal.h>
#include<sys/ipc.h>
#include<unistd.h>
#include<stdlib.h>
struct mybuf
{
int pid;
char buf[124];
};
void myfun()
{
printf("myfun\n");
}
int main()
{
int shmid;
int key;
struct mybuf *p;
int pid;
key = ftok("./myfifo",'b');
if(key < 0)
{
printf("create key failure\n");
return -1;
}
printf("create key sucess key = %X\n",key);
shmid = shmget(key,128,IPC_CREAT | 0777);
if(shmid<0)
{
printf("create share memory failure\n");
return -2;
}
printf("create share memory sucess shmid = %X\n",shmid);
signal(SIGUSR1,myfun);

p = (struct mybuf *)shmat(shmid,NULL,0);
if(p==NULL)
{
printf("shmat func failure\n");
return -3;
}

// get serve pid
// read share memory
pid = p->pid;
//write client pid to share memory
p->pid = getpid();
kill(pid,SIGUSR2);

while(1)
{
pause();//waits server process read
printf("client has read: %s\n",p->buf);
kill(pid,SIGUSR2);// server can write share memory
}
shmdt(p);
shmctl(shmid,IPC_RMID,NULL);
return 0;
}

ret

消息队列

概念

kernel中的消息队列

msgget创建消息队列

msgctl消息队列读取,设置,删除

msgsnd发送数据
其中消息类型要与队列中消息类型进行匹配

msgrcv读取消息队列

无亲缘关系的读写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/*************************************************************************
> File Name: msg_write.c
> Author: Merlynr
> Mail: lcq1013962426@gmail.com
> Created Time: 2023年02月02日 星期四 00时57分34秒
************************************************************************/

#include<stdio.h>
#include<sys/types.h>
#include<sys/msg.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
#include<stdlib.h>

struct msgbuf
{
long type;
char msg[124];
char next[4];
};

int main()
{
int msgid;
int readret;
int key;
struct msgbuf sendbuf,readbuf;
key = ftok("./myfifo",'a');
if(key<0)
{
printf("create key failure!\n");
return -1;
}
msgid = msgget(key,IPC_CREAT|0777);
if(msgid<0)
{
printf("create msgid failure!\n");
return -1;
}
system("ipcs -q");
//init send buf
sendbuf.type = 100;

//write
while(1)
{
memset(sendbuf.msg,0,124); //clear send buffer
printf("PLZ inout msg: ");
fgets(sendbuf.msg,124,stdin);
msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.msg),0);

}
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*************************************************************************
> File Name: msg_read.c
> Author: Merlynr
> Mail: lcq1013962426@gmail.com
> Created Time: 2023年02月02日 星期四 00时57分34秒
************************************************************************/

#include<stdio.h>
#include<sys/types.h>
#include<sys/msg.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
#include<stdlib.h>

struct msgbuf
{
long type;
char msg[124];
char next[4];
};

int main()
{
int msgid;
int readret;
int key;
struct msgbuf sendbuf,readbuf;
key = ftok("./myfifo",'a');
if(key<0)
{
printf("create key failure!\n");
return -1;
}
msgid = msgget(key,IPC_CREAT|0777);
if(msgid<0)
{
printf("create msgid failure!\n");
return -1;
}
system("ipcs -q");
//init send buf
sendbuf.type = 100;

//write
while(1)
{
memset(readbuf.msg,0,124); //clear read buffer
msgrcv(msgid,(void *)&readbuf,124,100,0);
printf("recv msg : %s\n",readbuf.msg);
}
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}

非亲缘关系的通信

信号灯

概念

信号灯:信号灯集合(可以包含多个信号灯)PC对象是一个信号灯集(多个信号量)

由两组值构成的某个信号灯集的内核数据结构

semget创建

semctl:获取、设置、删除信号灯

PV操作

利用信号灯进行通信

利用ftok创建key,然后构建信号灯。首先运行客户端,信号量初始化在客户端上,并进行V操作,所以信号量资源被释放,无法利用。下一步执行服务端,服务端先执行任务,然后发送P操作信息,由此分配资源给客户端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/*************************************************************************
> File Name: seg_server.c
> Author: Merlynr
> Mail: lcq1013962426@gmail.com
> Created Time: 2023年02月02日 星期四 22时41分35秒
************************************************************************/

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/sem.h>

union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *_buf;
};

int semid;
union semun mysemun;
struct sembuf mysembuf;

int main()
{
int i;
int key;
key = ftok("./myfifo",'a');
if(key<0)
{
printf("create key failure!");
return -1;
}
printf("create key sucess! key=%d\n",key);
semid = semget(key,3,IPC_CREAT|0777);
if(semid<0)
{
printf("create semid failure!");
return -1;
}
printf("create semid sucess! semid = %d\n",semid);
system("ipcs -s");

//init sem
// mysemun.val = 0;
// semctl(semid,0,SETVAL,mysemun);

mysembuf.sem_num = 0;
mysembuf.sem_flg = 0;
for(i=0; i<10; i++)
{
usleep(100);
printf("this is main func i=%d\n",i);
}
//v opt 客户端进行p操作处于暂停,服务端执行完任务之后进行v操作,然后客户端才可以进行分配资源,然后执行任务
//
mysembuf.sem_op =1;
semop(semid,&mysembuf,1);
while(1);
return 0;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*************************************************************************
> File Name: seg_client.c
> Author: Merlynr
> Mail: lcq1013962426@gmail.com
> Created Time: 2023年02月02日 星期四 22时41分35秒
************************************************************************/

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/sem.h>

union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *_buf;
};

int semid;
union semun mysemun;
struct sembuf mysembuf;

int main()
{
int i;
int key;
key = ftok("./myfifo",'a');
if(key<0)
{
printf("create key failure!");
return -1;
}
printf("create key sucess\n");
semid = semget(key,3,IPC_CREAT|0777);
if(semid<0)
{
printf("create semid failure!");
return -1;
}
printf("create semid sucess\n");
system("ipcs -s");

//init sem
mysemun.val = 0;
semctl(semid,0,SETVAL,mysemun);

mysembuf.sem_num = 0;
mysembuf.sem_flg = 0;
//p wait
mysembuf.sem_op=-1;
semop(semid,&mysembuf,1);
for(i=0; i<10; i++)
{
usleep(100);
printf("this is main func i=%d\n",i);
}
//v opt 客户端进行p操作处于暂停,服务端执行完任务之后进行v操作,然后客户端进行分配资源,然后执行任务
//
//mysembuf.sem_op =1;
//semop(semid,&mysembuf,1);
while(1);
return 0;

}

ret