多任务并发(2)IPC - 管道
进程间通信方式
一、管道
1、无名管道 pipe:适用于亲缘关系进程间的、一对一的通信
特点:
(1)管道文件:这个文件很特殊,其实就是一块内存,不能使用open打开,也不可以使用lseek,可以使用read write读写。
(2)半双工:同一时刻只能单方向传输数据
(3)大小为 64K
(4)关闭读端,能够正常写入数据 ,如果缓冲区已满,那么write会阻塞
(5)关闭写端,读取会阻塞
管道两端分别用描述符fd[0]和fd[1]来描述。其中fd[0]只能用于读,称为管道读端;fd[1]只能用于写,称为管道写端。
无名管道的通信方式如下代码所示:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
int main()
{
// 搞一个无名官道
int fd[2];
pipe(fd); // 将读写描述符分别放入fd[0]和fd[1]
// 搞一个子进程
pid_t pid = fork();
// 父进程: 将信息写入管道
if(pid > 0)
{
char *msg = "你好";
write(fd[1], msg, strlen(msg));
}
// 子进程: 将信息从管道读出来
if(pid == 0)
{
char msg[10];
bzero(msg, 10);
read(fd[0], msg, 10);
printf("读到: %s\n", msg);
}
close(fd[0]);
close(fd[1]);
return 0;
}
2、有名管道 fifo :适用于任何进程间的一对一、多对一的通信
特点:
FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。
有名管道的写端
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main(void)
{
// 创建、打开管道fifo
mkfifo("/tmp/myfifo", 0666);
int fd = open("/tmp/myfifo", O_RDWR);
// 写入数据到管道中
char buf[100];
while(1)
{
bzero(buf, 100);
if(fgets(buf, 100, stdin) == NULL)
break;
write(fd, buf, strlen(buf));
}
// 关闭文件,释放资源
close(fd);
return 0;
}
有名管道的读端
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main(void)
{
// 创建、打开管道fifo
mkfifo("/tmp/myfifo", 0666);
int fd = open("/tmp/myfifo", O_RDONLY);
// 将数据从管道中读出来
char buf[100];
while(1)
{
bzero(buf, 100);
if(read(fd, buf, 100) == 0)
{
printf("对方已经关闭,再见!\n");
break;
}
printf("收到: %s", buf);
}
// 关闭文件,释放资源
close(fd);
return 0;
}
二、信号
信号:异步通信方式(system-V IPC对象)
三、共享内存
共享内存:效率最高的通信方式
四、消息队列
消息队列:相当于带标签的增强版管道
五、信号量
信号量组:参数复杂,功能强大到臃肿
POSIX有名信号量:适用于多进程,参数简单,接口明晰,老少咸宜
POSIX无名信号量:适用于多线程,参数简单,接口明晰,童叟无欺
六、套接字
套接字 socket:适用于跨网络的进程间通信