进程间通信之管道
一、管道的概念
1.本质
(1)内核缓存区
(2)伪文件——不占用磁盘空间
2.特点
(1)两部分:
(2)读端,写端,对应两个文件描述符
(3)数据写端流入,读端流出
(4)操作管道的进程被销毁之后,管道自动释放
(5)管道默认阻塞的
3.管道的原理
1.内部实现的方式:队列
环形队列
特点:先进先出
缓冲区大小:
- 默认4K
- 大小会根据实际情况进程调整
4.管道的局限性
队列:数据只能读取一次,不能重复读取
半双工
匿名管道,适用于有血缘关系的进程
5.创建匿名管道:
int pipe(int fd[2])
fd 传出参数
fd[0]-读端
fd[1]-写端
6.父子进程使用管道进行通信
通信的步骤:
1.创建子进程
2.关闭子进程读端,关闭父进程的写端
代码
1 #include"utili.h"
2
3 int main()
4 {
5 int fd[2];
6 pid_t pid;
7 int res = pipe(fd);
8 if(res < 0)
9 {
10 printf("error\n");
11 return 1;
12 }
13 pid = fork();
14 if(pid < 0 )
15 {
16 printf("error\n");
17 }
18 else if(pid == 0)
19 {
20 close(fd[0]);
21 write(fd[1],"hello world\n",12);
22 }
23 else
24 {
25 close(fd[1]);
26 char buff[100];
27 int len = read(fd[0],buff,12);
28 printf("%s\n",buff);
29 wait(NULL);
30 }
31 return 0;
32 }
结果:
wz@wz-machine:~/linux/pipe$ gcc pipe3.c -o pipe3
wz@wz-machine:~/linux/pipe$ ./pipe3
hello world
二、FIFO(有名管道)
1.特点
- 有名管道
- 伪文件,在磁盘大小永远为0
- 在内核对应有一个缓冲区
半双工的通信方式
2.使用场景
没有血缘关系的进程间通信
3.创建方法命令:mkfifo 管道名
函数:mkfifo
4.fifo文件可以使用I/O函数进行操作open/close
- read/write
- 不能执行lseek操作
5.进程间通信(代码)
cli.c
“`
#include”../utili.h”
void SendData(int write_fd);
void RecvData(int read_fd);
int main()
{
//int read_fd;
int read_fd = open(write_fifo, O_RDONLY);
if(read_fd == -1)
{
perror(“open”);
return -1;
}
if(access(read_fifo, F_OK) == -1)
{
int res = mkfifo(read_fifo, O_CREAT|O_EXCL|0755);
if(res != 0)
{
perror("mkfifo");
return -1;
}
}
int write_fd = open(read_fifo, O_WRONLY);
if(write_fd == -1)
{
perror("open read fifo");
unlink(read_fifo);
return -1;
}
pid_t pid;
pid = fork();
if(pid == 0)
{
SendData(write_fd);
exit(0);
}
else if(pid > 0)
{
RecvData(read_fd);
int status;
wait(&status);
}
else
{
perror("fork");
}
if 0
char sendbuf[BUFFER_SIZE];
char recvbuf[BUFFER_SIZE];
while(1)
{
read(read_fd, recvbuf, BUFFER_SIZE);
printf("Ser:> %s\n",recvbuf);
printf("Cli:>");
scanf("%s",sendbuf);
if(strncmp(sendbuf, "quit", 4) == 0)
break;
write(write_fd, sendbuf, strlen(sendbuf)+1);
}
endif
unlink(read_fifo);
return 0;
}
void SendData(int write_fd)
{
char sendbuf[BUFFER_SIZE];
while(1)
{
printf(“Cli:>”);
scanf(“%s”, sendbuf);
if(strncmp(sendbuf, “quit”, 4) == 0)
break;
write(write_fd, sendbuf, strlen(sendbuf)+1);
}
}
void RecvData(int read_fd)
{
char recvbuf[BUFFER_SIZE];
while(1)
{
read(read_fd, recvbuf, BUFFER_SIZE);
printf(“Ser:> %s\n”,recvbuf);
}
}
cli.c
#include”../utili.h”
void SendData(int write_fd);
void RecvData(int read_fd);
int main(int argc, char *argv[])
{
if(access(write_fifo, F_OK) == -1)
{
int res = mkfifo(write_fifo, O_CREAT|O_EXCL|0755);
if(res != 0)
{
perror(“mkfifo”);
return -1;
};
}
printf("Server Wait Client Connect.......\n");
int write_fd; // fd[1]
write_fd = open(write_fifo, O_WRONLY|O_NONBLOCK);
if(write_fd == -1)
{
perror("poen write_fifo");
unlink(write_fifo);
return -1;
}
int read_fd;
while((read_fd = open(read_fifo, O_RDONLY)) == -1)
{
sleep(1);
}
printf("Client Connect Server OK.\n");
//char sendbuf[BUFFER_SIZE];
//char recvbuf[BUFFER_SIZE];
pid_t pid;
pid = fork();
if(pid == 0)
{
SendData(write_fd);
exit(0);
}
else if(pid > 0)
{
RecvData(read_fd);
int status;
wait(&status);
}
else
{
perror("fork");
}
if 0
while(1)
{
printf("Ser:>");
scanf("%s",sendbuf);
if(strncmp(sendbuf, "quit", 4) == 0)
break;
write(write_fd, sendbuf, strlen(sendbuf)+1);
read(read_fd, recvbuf, BUFFER_SIZE);
printf("Cli:> %s\n",recvbuf);
}
endif
unlink(write_fifo);
return 0;
}
void SendData(int write_fd)
{
char sendbuf[BUFFER_SIZE];
while(1)
{
printf(“Ser:>”);
scanf(“%s”, sendbuf);
if(strncmp(sendbuf, “quit”, 4) == 0)
break;
write(write_fd, sendbuf, strlen(sendbuf)+1);
}
}
void RecvData(int read_fd)
{
char recvbuf[BUFFER_SIZE];
while(1)
{
read(read_fd, recvbuf, BUFFER_SIZE);
printf(“Cli:> %s\n”,recvbuf);
}
}
“`
utili.h
#pragma once
#include<iostream>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdlib.h>
using namespace std;
#define BUFFER_SIZE 256
const char *write_fifo = "write_fifo";
const char *read_fifo = "read_fifo";