声明:
1、进程间通信,即进程与进程进行信息交换,两个进程必须处于运行,否则,通信结束
2、管道分为有名管道和无名管道都为半双工通信(数据流是单向的)
3、通信,即信息交互需求不同,方式不同(电话、发电报、发邮箱、微信等等)
普通管道
概念:
无名管道,只能用于解决具有共同祖先进程之间的通信(必须具有亲缘关系)
步骤:
1、fork出一个进程
2、pipie出一根管道
3、关闭不使用的文件描述符,操作,关闭使用过的文件描述符
半双工通信
84 #include<stdio.h>
85 #include<unistd.h>
86 #include<string.h>
87 int main()
88 {
89 char *msg="Hello Pipe";
90 int fd[2];
91 int res= pipe(fd);
92 pid_t pid = fork();
93 if(pid>0)
94 {
95 close (fd[0]);
96 write(fd[1],msg,strlen(msg)+1);
97 close (fd[1]);
98 }
99 else if(pid == 0)
100 {
101 close (fd[1]);
102 //建议
103 char buffer[256];
104 read(fd[0],buffer,256);
105 printf("From Parent Meg %s\n",buffer);
106 close (fd[0]);
107 }
108 else
109 perror("fork");
110 return 0;
111 }
用两根管道模拟全双工通信
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<stdlib.h>
4 #include<string.h>
5 #include<time.h>
6 int main()
7 {
8 char *parent_talk[]={"Hello","What time is it now?","I have no time ,byebye",NULL};
9 char *child_talk[]={"Hi","No problem","byebye",NULL};
10 int fd1[2];
11 int fd2[2];
12 int res = pipe(fd1);
13 if(res == -1)
14 {
15 printf("Creat Pipe1 Fail\n");
16 exit(1);
17 }
18 res = pipe(fd2);
19 if(res == -1)
20 {
22 exit(1);
23 }
24 pid_t pid = fork();
25 if(pid>0)
26 {
27 close(fd1[0]);
28 close(fd2[1]);
29 int i=0;
30 char buffer[256];
31 char *parent = parent_talk[i];
32 while(parent != NULL)
33 {
34 write(fd1[1],parent,strlen(parent)+1);
35 read(fd2[0],buffer,256);
36 printf("From Child >%s\n",buffer);
37 i++;
38 parent = parent_talk[i];
39 }
40 close(fd1[1]);
41 close(fd2[0]);
42 }
43 else if(pid == 0)
44 {
45 close(fd1[1]);
46 close(fd2[0]);
47 int i= 0;
48 char buffer[256];
49 char *child = child_talk[i];
50 while(child != NULL)
51 {
52 read(fd1[0],buffer,256);
53 printf("From Parent >%s\n",buffer);
54 if(i == 1)
55 {
56 time_t tt;
57 time(&tt);
58 char buffer[256];
59 //printf("%s",ctime(&tt));
60 memset(buffer,0,256);
61 sprintf(buffer,"%s %s",child,ctime(&tt));
62 //printf("buffer=%s\n",buffer);
63 write(fd2[1],buffer,strlen(buffer)+1);
64 }
65 else
66 {
67 write(fd2[1],child,strlen(child)+1);
68 }
69 i++;
70 child = child_talk[i];
71 }
72
73 close(fd1[0]);
74 close(fd2[1]);
75 }
76 else
77 {
78 perror("fork");
79 }
80 return 0;
81 }
获取当前日期和时间
//必须加上头文件#include<time.h>
time_t tt;//时间结构体
time(&tt);//时间种子
printf("%s",ctime(&tt));//获取时间
命名管道
概念:
命名管道:最大优点可以实现非亲缘关系的进程之间的通信,常见模型:服务器与客户端模型
理解:
命名管道即是对文件的操作,利用文件描述符来进行操作
步骤:
1、建立管道文件
2、打开管道,进行操作
3、关闭文件描述符
access函数,用于检查文件
//条件成立返回0,不成立返回-1
int access(const char *path, int amode);
amode:R_OK, W_OK, F_OK 用于检查
解释:
write_fifo和read_fifo,这两根管道,在服务器的角度命名
2、服务器一直开着,客户端可以断掉
3、实现一直良好通信原因是因为:write、read均属于阻塞函数
实现
一句一句回应
//uitli.h
#pragma once
2 #include<stdio.h>
3 #include<unistd.h>
4 #include<sys/stat.h>
5 #include<fcntl.h>
6 #include<string.h>
7 #include<stdlib.h>
8 const char *write_fifo ="write_fifo";
9 const char *read_fifo = "read_fifo";
//Ser.c
1 #include"utili.h"
2 int main()
3 {
4 //看管道文件是否存在,不存在新建
5 if(access(write_fifo,F_OK) != 0)
6 {
7 int res = mkfifo(write_fifo,O_CREAT|O_EXCL|0755);
8 if(res == -1)
9 {
10 perror(" fifo");
11 exit(1);
12 }
13 }
14 //打开管道
15 printf("12345678\n");
18 {
19 perror("write_fd");
20 exit(1);
21 }
22 int read_fd;
23 printf("222222222222222222\n");
//打开读管道,看客户端是否开启
24 while((read_fd=open(read_fifo,O_RDONLY))== -1)
25 {
26 printf("Client not start up.\n");
27 sleep(1);
28 }
//进行操作
29 char send_buf[256];
30 char recv_buf[256];
31 while(1)
32 {
33 printf("Ser>");
34 scanf("%s",send_buf);
35 write(write_fd,send_buf,strlen(send_buf)+1) ;
36 printf("Cli>");
37 read(read_fd,recv_buf,256);
38 printf("%s\n",recv_buf);
39 }
//关闭文件描述符
40 close(write_fd);
41 colse(read_fd);
42 return 0;
43 }
//Cli.c
1 #include"utili.h"
2 int main()
3 {
4 printf("rdrdrdrdrdrdrdrdrrd\n");
5 int read_fd;
//打开读管道 (对于服务器为写管道)
6 read_fd = open(write_fifo,O_RDONLY);
7 if(read_fd == -1)
8 {
9 perror("read_fd");
10 exit(1);
11 }
//判断读文件书否存在,不存在,则新建
12 if(access(read_fifo,F_OK) !=0)
13 {
int res = mkfifo(read_fifo,O_CREAT|O_EXCL|0755);
15 if(res == -1)
16 {
19 exit(1);
20 }
21 }
//打开写管道(对于服务器是写管道)
22 int write_fd = open(read_fifo,O_WRONLY);
23 if(write_fd == -1)
24 {
25 perror("write_fd");
26 exit(1);
27 }
28 char send_buf[256];
29 char recv_buf[256];
30 while(1)
31 {
32 read(read_fd,recv_buf,256);
33 printf("Ser>%s\n",recv_buf);
34 printf("Cli>");
35 scanf("%s",send_buf);
36 write(write_fd,send_buf,strlen(send_buf+1));
37 }
38 close(read_fd);
39 colse(write_fd);
40 return 0;
41 }
//Makefile
1 all: ser cli
2 ser:
3 gcc -o ser ser.c
4 cli:
5 gcc -o cli cli.c
6 clean:
7 rm ser cli
8
result
可以重复发送
原理:利用多进程实现,用两个子进程来实现,一个专门用来 读,另一个专门用来写
实现
//utili.h
1 #pragma once
2 #include<stdio.h>
3 #include<unistd.h>
4 #include<sys/stat.h>
5 #include<fcntl.h>
6 #include<string.h>
7 #include<stdlib.h>
8 const char *write_fifo ="write_fifo";
9 const char *read_fifo = "read_fifo";
10 void write_msg(int fd);
11 void read_msg(int fd);
12
利用多进程实现可以发多句信息
//ser.c
1 #include"utili.h"
2 int main()
3 {
4 //创建管道
5 if(access(write_fifo,F_OK) != 0)
6 {
7 int res = mkfifo(write_fifo,O_CREAT|O_EXCL|0755);
8 if(res == -1)
9 {
10 perror(" fifo");
11 exit(1);
12 }
13 }
14 //打开管道
15 int write_fd = open(write_fifo,O_WRONLY);
16 if(write_fd == -1)
17 {
18 perror("write_fd");
19 exit(1);
20 }
21 int read_fd;
22 while((read_fd=open(read_fifo,O_RDONLY))== -1)
23 {
24 printf("Client not start up.\n");
25 sleep(1);
26 }
27 pid_t pid = fork();
//2
28 if(pid == 0)
29 {
30 //write
31 write_msg(write_fd);
32 }
33 else if(pid > 0)
34 {
35 pid = fork();
//1
36 if(pid == 0)
37 {
38 //read
39 read_msg(read_fd);
40 }
// 0
41 else if(pid >0)
42 {
43 int status;
44 wait(&status);
45 close(write_fd);
46 close(read_fd);
47 }
48 else
49 perror("fork");
50 }
51 else
52 {
53 perror("fork");
54 }
55 return 0;
56 }
57 void write_msg(int fd)
58 {
59 char buf[256];
60 while(1)
61 {
62
63 printf("Ser>");
64 scanf("%s",buf);
65 if(!strcmp(buf,"quit"))
66 {
67 break;
68 }
69 write(fd,buf,strlen(buf)+1);
70 }
71 }
72 void read_msg(int fd)
73 {
74 char buf[256];
75 while(1)
76 {
77 read(fd,buf,256);
78 printf("Cli>%s\n",buf);
79 }
80 }
//Cli.c
1 #include"utili.h"
2 int main()
3 {
int read_fd = open(write_fifo,O_RDONLY);
4 if(read_fd == -1)
5 {
6 perror("read_fd");
7 exit(1);
8 }
9 if(access(read_fifo,F_OK) !=0)
10 {
11 int res = mkfifo(read_fifo,O_CREAT|O_EXCL|0755);
12 if(res == -1)
13 {
14 perror("read_fifo");
15 close(read_fd);
16 exit(1);
17 }
18 }
19 int write_fd = open(read_fifo,O_WRONLY);
20 if(write_fd == -1)
21 {
22 perror("write_fd");
23 exit(1);
24 }
25 pid_t pid = fork();
//2
26 if(pid==0)
27 {
28 //write
29 write_msg(write_fd);
30 }
31 else if(pid>0)
32 {
33 pid = fork();
// 1
34 if(pid == 0)
35 {
36 //read
37 read_msg(read_fd);
38 }
//0
39 else if(pid >0)
40 {
41 int status;
42 wait(&status);
43 }
44 else
45 {
46 perror("fork");
47 }
48 }
49 else
50 {
51 perror("fork");
52 }
53
54
55 return 0;
56 }
57 void read_msg(int fd)
58 {
59 char buf[256];
60 while(1)
61 {
62 read(fd,buf,256);
63 printf("Ser>%s\n",buf);
64 }
65
66 }
67 void write_msg(int fd)
68 {
69 while(1)
70 {
71
72 printf("Cli>");
73 char buf[256];
74 scanf("%s",buf);
75 if(!strcmp(buf,"quit"))
76 break;
77 write(fd,buf,strlen(buf)+1);
78 }
79 }
阻塞函数&非阻塞函数
阻塞函数:我要以写打开,必须对面一定要有为读打开,不然阻塞在写操作;若要以只读方式打开,必须有以为读打开的写文件,不然一直阻塞在读操作
非阻塞函数:虽然不阻塞,但是打开又不成功
非阻塞函数:
1、read() write()
总结:
1、熟悉pipe、fifo管道以及优缺点
2、掌握常用的几个函数ctime 、access函数
3、阻塞函数与非阻塞函数
4、使用多进程实现重复发消息,用不同的进程负责读或者写操作