1、命名管道
- 命名管道的限制就是只能在具有共同祖先的进程间通信
- 如果我们想在不相关的进程间交换数据,可以用FIFO文件来做这项工作,称为命名管道
- 命名管道是一种特殊类型的文件
创建命名管道
(1)命令行方法
mkfifo filename
(2)程序里创建
int mkfifo(const char * filename, mode_t mode);
int main()
{
mkfifo("file", 0644);
return 0;
}
匿名管道与命名管道的区别
- 匿名管道由pipe函数创建并打开
- 命名管道用mkfifo函数创建,用open打开
- FIFO与pipe之间唯一的区别在于创建和打开方式不同,其他语义相同
命名管道的打开规则
- 如果当前操作是为读而打开FIFO时
O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO
O_NONBLOCK enable:立刻返回成功 - 如果当前操作是为写而打开FIFO时
O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO
O_NONBLOCK enable:立刻返回失败,错误码ENXIO
命名管道实现文件拷贝
读源文件,写入命名管道
#include<iostream>
#include<stdio.h>
#include<errno.h>
#include<cstring>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define SIZE 1024
#define ERR_EXIT(m) do{perror(m);exit(EXIT_FAILURE);}while(0)
using namespace std;
void mk_fifo()
{
mkfifo("tp", 0644);
}
void rdfile_wrTofifo()
{
int infd = open("file", O_RDONLY);
if(infd == -1)
{
ERR_EXIT("open_file");
}
int outfd = open("tp", O_WRONLY);
if(outfd == -1)
{
ERR_EXIT("open_tp");
}
char buf[SIZE] = {};
int len;
while((len = read(infd, buf, SIZE)) > 0)
{
write(outfd, buf, len);
}
close(infd);
close(outfd);
}
int main()
{
mk_fifo();
rdfile_wrTofifo();
return 0;
}
读命名管道,写入目标文件
#include<iostream>
#include<stdio.h>
#include<errno.h>
#include<cstring>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define SIZE 1024
#define ERR_EXIT(m) do{perror(m);exit(EXIT_FAILURE);}while(0)
using namespace std;
void rdfifo_wrTofile()
{
int infd = open("tp", O_RDONLY);
if(infd == -1)
{
ERR_EXIT("open_tp");
}
int outfd = open("file.bak", O_WRONLY|O_CREAT|O_TRUNC, 0644);
if(outfd == -1)
{
ERR_EXIT("open_file_bak");
}
char buf[SIZE] = {};
int len;
while((len = read(infd, buf, SIZE)) > 0)
{
write(outfd, buf, len);
}
close(infd);
close(outfd);
unlink("tp");
}
int main()
{
rdfifo_wrTofile();
return 0;
}
命名管道实现server/client通信
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define SIZE 1024
#define ERR_EXIT(m) do{perror(m);exit(EXIT_FAILURE);}while(0)
using namespace std;
void mk_fifo()
{
umask(0);
if(mkfifo("mypipe", 0644) < 0)
{
ERR_EXIT("mypipe");
}
}
void serverPipe()
{
int rfd = open("mypipe", O_RDONLY);
if(rfd < 0)
{
ERR_EXIT("open_rfd");
}
char buf[SIZE] = {};
while(1)
{
cout<<"Waiting......"<<endl;
size_t len = read(rfd, buf, SIZE);
if(len == 0)
{
cout<<"client quit!......"<<endl;
unlink("mypipe");
exit(EXIT_SUCCESS);
}
else if(len > 0)
{
buf[len-1] = '\0';
cout<<buf<<endl;
}
else
{
ERR_EXIT("read_rfd");
}
}
close(rfd);
}
int main()
{
mk_fifo();
serverPipe();
return 0;
}
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define SIZE 1024
#define ERR_EXIT(m) do{perror(m);exit(EXIT_FAILURE);}while(0)
using namespace std;
void clientPipe()
{
int wfd = open("mypipe", O_WRONLY);
if(wfd < 0)
{
ERR_EXIT("open_wfd");
}
char buf[SIZE] = {};
while(1)
{
cout<<"Enter#";
fflush(stdout);
size_t len = read(0, buf, SIZE);
if(len <= 0)
{
ERR_EXIT("read_wfd");
}
else if(len > 0)
{
buf[len] = '\0';
write(wfd, buf, strlen(buf));
}
}
close(wfd);
}
int main()
{
clientPipe();
return 0;
}
2、其他几种进程间通信方式
System V 共享内存
共享内存是最快的IPC形式,一旦这样的内存映射到共享他的进程的地址空间,这些进程间数据传递不再涉及内核,进程不再通过执行进入内核的系统调用来传递数据
System V 消息队列
- 消息队列提供了一个从一个进程向另一个进程发送一块数据的方法
- 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值
- IPC资源必须删除,否则不会自动清除。System V IPC资源的生命周期随内核
System V 信号量
信号量主要用于同步和互斥
- 由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程竞争使用这些资源,进程的这种竞争关系称为进程的互斥
- 系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源
- 在进程中涉及到互斥资源的程序段称为临界区
- IPC资源必须删除,否则不会自动清除。System V IPC资源的生命周期随内核