0%

实验三-进程通信

pipe

创建管道要在创建子进程之前

创建管道

1
2
int fd[2];
pipe(fd);

其中fd[1]用来往管道里写,fd[1]用来向管道中读

向管道中写

1
write(fd1[1], inLine, LENGTH);

fd[1]表示现在是写,inLine是写入管道字符串的字符数组,LENGTH是写入的长度(一般和写入的长度相同)

从管道中读

1
read(fd2[0], outLine, LENGTH);

fd2[0]表示现在是读,outLine是从保存从管道中读取的字符数组,LENGTH是从管道中读取的长度

完整代码

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
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define LENGTH 1024
int main() {
int fd1[2];
char outLine[LENGTH];
int fd2[2];
char inLine[LENGTH];
pipe(fd1);
pid_t p1 = fork();
if(p1 == -1) {
printf("create p1 failed\n");
} else if(p1 == 0) {
sprintf(inLine, "Child 1 is sending a message!");
write(fd1[1], inLine, LENGTH);
exit(0);
} else {
read(fd1[0], outLine, LENGTH);
printf("%s\n", outLine);
pipe(fd2);
pid_t p2 = fork();
if(p2 == -1) {
printf("create p2 failed\n");
} else if(p2 == 0) {
sprintf(inLine, "Child 2 is sending a message!");
write(fd2[1], inLine, LENGTH);
exit(0);
} else {
read(fd2[0], outLine, LENGTH);
printf("%s\n", outLine);
}
return 0;
}
return 0;
}

消息队列

写入消息队列

创建消息队列

创建消息结构体,定义一个全局的消息结构体

1
2
3
4
struct msgbuf{
long mtype;
char mtext[LENGTH];
}msgbuf;

再在全局定义一个消息队列的键,这个键就是表示消息队列的编号

1
int MSG_KEY;

然后利用msgget创建消息队列

1
msgNum = msgget(MSG_KEY, IPC_CREAT | 0666);

详细解释:

  • MSG_KEY作用:

    MSG_KEY 应该是一个用于唯一标识消息队列的键值,但是它在代码中并没有被定义。通常情况下,可以使用 ftok() 函数来生成一个唯一的键值

  • IPC_CREAT作用

    IPC_CREAT 表示如果消息队列不存在则创建

  • 0666作用

    表示消息队列的权限

    在 Linux/Unix 中,文件权限通常以八进制数表示。每个权限对应的数值如下:

    • 0:没有任何权限
    • 1:执行权限(可执行文件)
    • 2:写权限(写入文件)
    • 4:读权限(读取文件)

    这些权限可以组合使用,通过将对应的数值相加来表示多个权限的组合。例如:

    • 3:执行权限和写权限(1 + 2)
    • 5:执行权限和读权限(1 + 4)
    • 6:写权限和读权限(2 + 4)
    • 7:执行权限、写权限和读权限(1 + 2 + 4)

    0666 中,表示的权限是:

    • 0:表示特殊权限位,通常为文件类型或文件特性(如设备文件、管道、套接字等),在这里不涉及文件类型的权限,因此这个位置通常用0填充。
    • 666:表示读权限和写权限,即文件的所有者、所属组和其他用户都有读和写的权限。

整条语句的作用是用来创建消息队列, 可以理解返回的是消息队列的地址

将缓存中消息发送到消息队列

1
msgsnd(msgNum, &msgbuf, LENGTH, 0);
  • msNum:消息队列的标识符,它是由 msgget 函数返回的值。
  • &msgbuf:一个指向消息缓冲区的指针,消息将从这个缓冲区中发送。
  • 1024:消息的大小,以字节为单位。在这里,消息的大小为 1024 字节。
  • 0:这是一个标志参数,用于指定在发送消息时的行为。在这里,它是一个控制参数,通常可以用来设置一些特殊的行为,但在这个例子中被设置为 0,表示没有设置特殊的行为。

代码

1
2
3
4
5
6
7
8
9
10
void client() {
msgNum = msgget(MSG_KEY, IPC_CREAT | 0666);
// 上面语句用来创建消息队列, 可以理解返回的是消息队列的地址,注意与msgNum的区别
printf("input a message\n");
scanf("%s", msgbuf.mtext);
msgbuf.mtype = 1;
// 上面语句用来将要发送的消息暂时存入缓冲区,并设置这种消息的类型为1
msgsnd(msgNum, &msgbuf, LENGTH, 0); // 将内存中消息发送到消息队列中
}

从消息队列中读取

获取消息队列

1
msgNum = msgget(MSG_KEY, IPC_CREAT | 0666);

从消息队列中读取

1
msgrcv(msgNum, &msgbuf, LENGTH, 0, 0);
  • msgNum:消息队列的标识符,它是由 msgget() 函数返回的值。
  • &msgbuf:一个指向消息缓冲区的指针,用于存储接收到的消息。
  • LENGTH:消息的最大长度,以字节为单位。在这里,消息的最大长度被设置为 1024 字节。
  • 0:这是一个消息的类型,它指定了要接收的消息的类型。在这里,设置为 0 表示接收队列中的第一个消息。
  • 0:这是一个标志参数,用于指定在接收消息时的行为。在这里,它是一个控制参数,表示没有设置特殊的行为。

代码

1
2
3
4
5
6
void server() {
msgNum = msgget(MSG_KEY, IPC_CREAT | 0666);
msgrcv(msgNum, &msgbuf, LENGTH, 0, 0);
printf("The save line is %s\n", msgbuf.mtext);
msgctl(msgNum, IPC_RMID, 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
//
// Created by pilot on 24-4-11.
//
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <wait.h>
#include <stdlib.h>

#define LENGTH 1024
#define MSG_KEY 24
struct msgbuf{
long mtype;
char mtext[LENGTH];
}msgbuf;
int msgNum = 0; //利用全局变量定义消息队列的序号,这个是1个键,相当于消息队列的编号
void client() {
msgNum = msgget(MSG_KEY, IPC_CREAT | 0666);
// 上面语句用来创建消息队列, 可以理解返回的是消息队列的地址,注意与msgNum的区别
printf("input a message\n");
scanf("%s", msgbuf.mtext);
msgbuf.mtype = 1;
// 上面语句用来将要发送的消息暂时存入缓冲区,并设置这种消息的类型为1
msgsnd(msgNum, &msgbuf, LENGTH, 0); // 将内存中消息发送到消息队列中
}
void server() {
msgNum = msgget(MSG_KEY, IPC_CREAT | 0666);
msgrcv(msgNum, &msgbuf, LENGTH, 0, 0);
printf("The save line is %s\n", msgbuf.mtext);
msgctl(msgNum, IPC_RMID, 0);
}

int main() {
pid_t p1 = fork();
if(p1 == -1) {
printf("create p1 failed\n");
} else if(p1 == 0) {
wait(0);
printf("this is child process1\n");
server();
printf("process1 end\n");
} else {
pid_t p2 = fork();
if(p2 == -1) {
printf("create p2 failed\n");
} else if(p2 == 0) {
printf("this is child process2\n");
client();
printf("process2 end\n");
} else {
wait(0);
printf("task end\n");
}
}
return 0;
}