1.进程间通信
每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程A把数据从用户空间拷到内核缓冲区,进程B再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信。

不同进程间的通信本质:进程之间可以看到一份公共资源;而提供这份资源的形式或者提供者不同,造成了通信方式不同,而 pipe就是提供这份公共资源的形式的一种。
2.匿名管道
2.1管道的创建
管道是由调用pipe函数来创建
#include
int pipe (int fd[2]); //返回:成功返回0,出错返回-1
fd参数返回两个文件描述符,fd[0]指向管道的读端,fd[1]指向管道的写端。fd[1]的输出是fd[0]的输入。
2.2管道如何实现进程间的通信
(1)父进程创建管道,得到两个⽂件描述符指向管道的两端
(2)父进程fork出子进程,⼦进程也有两个⽂件描述符指向同⼀管道。
2.3如和用代码实现管道通信
- #include
- #include
- #include
- #include
- int main()
- {
- int fd[2];
- int ret = pipe(fd);
- if (ret == -1)
- {
- perror(”pipe error\n”);
- return 1;
- }
- pid_t id = fork();
- if (id == 0)
- {
//child - int i = 0;
- close(fd[0]);
- char *child = “I am child!”;
- while (i<5)
- {
- write(fd[1], child, strlen(child) + 1);
- sleep(2);
- i++;
- }
- }
- else if (id>0)
- {
//father - close(fd[1]);
- char msg[100];
- int j = 0;
- while (j<5)
- {
- memset(msg,’\0’,sizeof(msg));
- ssize_t s = read(fd[0], msg, sizeof(msg));
- if (s>0)
- {
- msg[s – 1] = ’\0’;
- }
- printf(”%s\n”, msg);
- j++;
- }
- }
- else
- {
//error - perror(”fork error\n”);
- return 2;
- }
- return 0;
- }
运行结果:
每隔2秒打印一次I am child! 并且打印了五次。

2.4管道读取数据的四种的情况
如果一个管道读端一直在读数据,而管道写端的引⽤计数⼤于0决定管道是否会堵塞,引用计数大于0,只读不写会导致管道堵塞。
(4)读端读了一部分数据,不读了且关闭fd[0],写端一直在写且f[1]还保持打开状态。

- #include
- #include
- #include
- #include
- int main()
- {
- int fd[2];
- int ret = pipe(fd);
- if (ret == -1)
- {
- perror(”pipe error\n”);
- return 1;
- }
- pid_t id = fork();
- if (id == 0)
- {
//child - int i = 0;
- close(fd[0]);
- char *child = “I am child!”;
- while (i<10)
- {
- write(fd[1], child, strlen(child) + 1);
- sleep(2);
- i++;
- }
- }
- else if (id>0)
- {
//father - close(fd[1]);
- char msg[100];
- int status = 0;
- int j = 0;
- while (j<5)
- {
- memset(msg, ’\0’, sizeof(msg));
- ssize_t s = read(fd[0], msg, sizeof(msg));
- if (s>0)
- {
- msg[s – 1] = ’\0’;
- }
- printf(”%s %d\n”, msg, j);
- j++;
- }
- //写方还在继续,而读方已经关闭它的读端
- close(fd[0]);
- pid_t ret = waitpid(id, &status, 0);
- printf(”exitsingle(%d),exit(%d)\n”, status & 0xff, (status >> 8) & 0xff);
- //低八位存放该子进程退出时是否收到信号
- //此低八位子进程正常退出时,退出码是多少
- }
- else
- {
//error - perror(”fork error\n”);
- return 2;
- }
- return 0;
- }
运行结果:

使用kill -l 查看13号信号,可以知道13号信号代表SIGPIPE。
2.5管道特点
1.管道只允许具有血缘关系的进程间通信,如父子进程间的通信。 2.管道只允许单向通信。 3.管道内部保证同步机制,从而保证访问数据的一致性。 4.面向字节流 5.管道随进程,进程在管道在,进程消失管道对应的端口也关闭,两个进程都消失管道也消失。
2.6管道容量大小
#include
#include
#include
#include
int main() { int fd[2]; int ret = pipe(fd); if (ret == -1) { perror("pipe error\n"); return 1; } pid_t id = fork(); if (id == 0) {
//child int i = 0; close(fd[0]); char *child = "I am child!"; while (++i) { write(fd[1], child, strlen(child) + 1); printf("pipe capacity: %d\n", i*(strlen(child) + 1)); } close(fd[1]); } else if (id>0) {
//father close(fd[1]); waitpid(id, NULL, 0); } else {
//error perror("fork error\n"); return 2; } return 0; }
可以看到写到65520之后管道堵塞了,而65536即为64K大小即为管道的容量(由于代码问题,少统计一次数据)。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/212220.html原文链接:https://javaforall.net
