进程间通信的目的
进程间通信的本质理解
进程间通信的必要性
??单进程无法使用并发能力,更加无法实现多进程协同。
管道是进程通信的其中一种,管道分为两种:
??父进程fork之后,父进程会copy一份files_struct给子进程,但是父子进程的文件描述符依旧是指向同一份文件,而这个文件就叫做管道。
??管道某种意义上来说不是文件,是一种方式,进行交流的数据作为临时数据放在内存,实际上是由内核维护的一个缓冲区,在内核中被称为管道缓存,当交流结束后,临时数据就会被释放。所以也可以把管道看作是一个缓冲区。
#include <unistd.h>
功能:创建一无名管道
原型
int pipe(int fd[2]);
参数
fd
:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0,失败返回错误代码
如何做到让不同的进程看到同一份资源?
:fork后让子进程继承—>能够让具有血缘关系的进程进行进程间通信—>常用于父子进程
下面这是一个简易的匿名管道的实现,当使用pipe函数时,管道文件是通过 pipe 系统调用创建的。具体来说,pipe 系统调用会在内核中创建一个管道,并返回两个文件描述符,这两个文件描述符分别用于读取和写入管道。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <cstdlib>
int main()
{
int fd[2];
int retpp = pipe(fd);
if (retpp == -1)
{
perror("pipe");
exit(1);
}
int fk = fork();
if (fk < 0)
{
perror("fork");
exit(2);
}
if (fk == 0)
{
// child: 作读端,首先得关闭写端
close(fd[1]);
char buf[1024];
read(fd[0], buf, sizeof(buf));
printf("child: %s\n", buf);
}
if (fk > 0)
{
// parent:作写端,首先得关闭读端
close(fd[0]);
char *bufp = "qwweereewrrere";
write(fd[1], bufp, strlen(bufp));
return 0;
}
}
可不可以改变管道文件呢?
下面的代码将文件t.txt作为管道文件。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd[2];
int retpp = pipe(fd);
if (retpp == -1)
{
perror("pipe");
exit(1);
}
int fk = fork();
if (fk < 0)
{
perror("fork");
exit(2);
}
int fd1 = open("F:\\t.txt", O_RDWR | O_CREAT, 0666);
if (fd1 < 0)
{
perror("open");
exit(3);
}
if (fk == 0)
{
// child: 作读端,首先得关闭写端
close(fd[1]);
char buf[1024];
dup2(fd[0], fd1);
read(fd[0], buf, sizeof(buf));
printf("%s\n", buf);
}
if (fk > 0)
{
// parent:作写端,首先得关闭读端
close(fd[0]);
const char *bufp = "qwweereewrrere";
dup2(fd[1], fd1);
write(fd[1], bufp, strlen(bufp));
return 0;
}
}
用fork来共享管道原理
站在文件描述符角度-深度理解管道
站在内核角度-管道本质
管道提供了访问控制
命名管道可以从命令行上创建,命令行方法是使用下面这个命令:
mkfifo filename
命名管道也可以从程序里创建,相关函数有:
int mkfifo(const char *filename,mode_t mode);
比如我们可以这么创建命名管道:
int main(int argc, char *argv[])
{
mkfifo("p2", 0644);
return 0;
}
匿名管道与命名管道的区别
命名管道的打开规则
??下面的代码实现了客户端向命名管道中写入信息,服务端从命名管道中将数据读取出来并打印在终端屏幕上。
// server.cpp
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
int main()
{
srand((unsigned int)time(NULL));
if (mkfifo("shard", 0666) < 0)
{
perror("mkfifo");
exit(1);
}
int sfd = open("shard", O_WRONLY, 0666);
if (sfd < 0)
{
perror("server_open");
exit(2);
}
while (1)
{
int a = rand() % 1000;
char server_put[1024] = {'\0'};
sprintf(server_put, "%d", a);
printf("server: %s\n", server_put);
write(sfd, server_put, sizeof(server_put));
sleep(2);
}
return 0;
}
// client
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
int main()
{
srand((unsigned int)time(NULL));
int cfd = open("shard", O_RDONLY, 0666);
if (cfd < 0)
{
perror("client_open");
exit(2);
}
while (1)
{
char client_in[1024];
read(cfd, client_in, sizeof(client_in));
printf("client: %s\n", client_in);
sleep(1);
}
return 0;
}
// makefile
.PHANY:all
all: server client
server:server.cpp
g++ -o $@ $^
client:client.cpp
g++ -o $@ $^
.PHANY:clean
clean:
rm -f client server shard
????😄 创作不易,你的点赞和关注都是对我莫大的鼓励,再次感谢您的观看😄