No.1 进程间通信的八种方式
-
- 普通文件
两个进程访问同一个文件 有先后顺序
- 普通文件
-
- 文件映射虚拟内存
父子进程之间
- 文件映射虚拟内存
-
- 管道
-
- 信号
-
- IPC之 共享内存
-
- IPC之 消息队列
-
- IPC之 消息量(旗语)
-
- 网络通信
No.2 文件映射虚拟内存通讯
-
- 创建文件
-
- 文件映射成虚拟内存在fork之前
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <time.h>
/*
父进程 持续不断滚动输出
子进程 持续不断等待用户输入
按下空格键 停止滚动 再按以下恢复滚动
*/
//文件映射虚拟内存
int main()
{
//1. 创建文件
int fd = open("mmap.dat",O_CREAT|O_RDWR,0777);
ftruncate(fd,4);
//2. 文件映射成虚拟内存在fork之前
int*p = (int*)mmap(NULL,4,PROT_READ|PROT_WRITE,
MAP_SHARED,fd,0);
*p = 0;
if(fork())//父进程
{
srand(time(NULL));
while(1)
{
while(*p);//开关
usleep(1000); //10ms
printf("%08d\n",rand()%100000000);
}
}
else//子进程
{
char ch;
while(1)
{
read(0,&ch,1);
if('\n'== ch)//回车停止输出
if( 0==*p) *p = 1;
else *p=0;
}
}
}
No.3 管道(同一主机之上用得比较多)
-
管道:管道是一个文件 (FIFO First In First Out)以文件形式存在的一个特殊队列
-
匿名管道:没有名字
专门用于父子之间,直接使用文件描述符号,
不需要文件名
fd[0] 用来读
fd[1] 用来写
//1 创建两个文件描述符号 (两个int整形)
int fd[2];
//2 把文件描述符号变成管道
pipe
//3 使用管道进行通信//4 关闭
close(fd[0]);
close(fd[1]);
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main()
{
//1 创建两个文件描述符号 (两个int整形)
int fd[2];
//2 把文件描述符号变成管道
pipe(fd);
//3 使用管道进行通信
if(fork())
{
char temp[1024];
int r;
while(1)
{
r = read(fd[0],temp,1023);
if(r>0)
{
temp[r] = 0;//添加结束符号
printf(">> %s\n",temp);//打印数据
}
}
}
else
{
char temp[1024];
while(1)
{
memset(temp,0,1024);
printf("你要发送点啥:");
scanf("%s",temp);
write(fd[1],temp,strlen(temp));
}
}
//4 关闭
close(fd[0]);
close(fd[1]);
}
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main()
{
//1 创建两个文件描述符号 (两个int整形)
int fd[2];
//2 把文件描述符号变成管道
pipe(fd);
//3 使用管道进行通信
if(fork())
{
char temp[1024];
int r;
while(1)
{
r = read(fd[0],temp,1023);
if(r>0)
{
temp[r] = 0;//添加结束符号
printf(">> %s\n",temp);//打印数据
}
}
}
#if 0
else
{
char temp[1024];
while(1)
{
memset(temp,0,1024);
printf("你要发送点啥:");
scanf("%s",temp);
write(fd[1],temp,strlen(temp));
}
}
#else
else
{
char temp[1024];
int r=0;
while(1)
{
sprintf(temp,"hahahahah:%d\n",r++);
write(fd[1],temp,strlen(temp));
sleep(1);
}
}
#endif
//4 关闭
close(fd[0]);
close(fd[1]);
}
- 有名管道:有名字
可以在同一主机上不同进程之间操作 有具体的文件
A B
//1. 创建管道文件(mkfifo)
//2. 打开管道文件 //1. 打开管道文件
open
//3. 使用管道文件(读) //2. 使用管道文件(写)
read write
//4. 关闭 //3. 关闭
close
//5. 删除管道文件
unlink
管道一边打开后阻塞 等待另外一边打开 结束open函数
A
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
//1. 创建管道文件(mkfifo)
int r = mkfifo("test.pipe",0777);
if(0==r) printf("创建管道文件:%m\n");
else printf("创建管道文件失败:%m\n"),exit(-1);
//2. 打开管道文件
int fd = open("test.pipe",O_WRONLY);
if(-1==fd) printf("打开管道文件失败:%m\n"),exit(-1);
else printf("打开管道文件成功:%m\n");
//3. 使用管道文件(写)
int n;
char buff[56];
int d=0;
while(5>d)
{
sprintf(buff,"hahahaha:%d",d++);
write(fd,buff,strlen(buff));
sleep(1);
}
//4. 关闭
close(fd);
//5. 删除管道文件
unlink("test.pipe");
return 0;
}
B
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
//1. 打开管道文件
int fd = open("test.pipe",O_RDONLY);
if(-1==fd) printf("打开管道文件失败:%m\n"),exit(-1);
else printf("打开管道文件成功:%m\n");
//2. 使用管道文件(读)
char buff[56];
int r;
while(1)
{
memset(buff,0,56);
r = read(fd,buff,55);
if(r>0)
{
buff[r] = 0;
printf(">> %s\n",buff);
}
}
//3. 关闭
close(fd);
return 0;
}
Copy on write(写时拷贝)
只有当需要写的时候才拷贝,只进行读操作,不进行拷贝。
子进程拷贝父进程所有代码
父进程中有个int n;
当后面的程序没有改n的值的时候,操作系统中只有一份n,只有当要修改n的值的时候,才进行拷贝.
传输文件文件到Test目录下
A
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
int main(int argc,char* argv[])
{
if(argc!=2) return 0;
//1. 创建管道文件(mkfifo)
int r = mkfifo("test.pipe",0777);
if(0==r) printf("创建管道文件:%m\n");
else printf("创建管道文件失败:%m\n"),exit(-1);
//2. 打开管道文件
int fd = open("test.pipe",O_WRONLY);
if(-1==fd) printf("打开管道文件失败:%m\n"),exit(-1);
else printf("打开管道文件成功:%m\n");
//3. 使用管道文件(写)
//3.1 获取要传输的文件信息
struct stat st ;
stat(argv[1],&st);
//3.2 传送文件名长度
int Size = strlen(argv[1]);
write(fd,&Size,4);
//3.3 传送文件名
write(fd,argv[1],strlen(argv[1]));
printf("%s %ld\n",argv[1],st.st_size);
//3.4 传送文件大小
Size = st.st_size;
write(fd,&Size,sizeof Size);
//3.5 打开文件然后传送文件
int fw = open(argv[1],O_RDONLY);
r=0;
char c;
while(1)
{
r = read(fw,&c,1);
if(r!=1)
{
printf("拷贝完成!\n");
break;
}
write(fd,&c,1);
}
//4. 关闭
close(fd);
close(fw);
//5. 删除管道文件
unlink("test.pipe");
return 0;
}
B
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
//1. 打开管道文件
int fd = open("test.pipe",O_RDONLY);
if(-1==fd) printf("打开管道文件失败:%m\n"),exit(-1);
else printf("打开管道文件成功:%m\n");
//2. 使用管道文件(读)
//2.1 获取文件名长度
int r = 0;
read(fd,&r,4);
char* name = (char*)malloc((r+1));
//2.2 获取文件名
r = read(fd,name,r);
name[r+1] = 0;
printf("%s\n",name);
//2.3 获取文件内容长度
int Size;
read(fd,&Size,4);
printf("size:%d\n",Size);
//2.4 创建文件夹Test
system("mkdir Test");
//2.5 链接文件目录
char demo[1024];
sprintf(demo,"./Test/%s",name);
printf("%s\n",demo);
//2.6 创建文件并且进行接受
int fw = open(demo,O_WRONLY|O_CREAT,0666);
int n=0;
char c;
while(n<=Size)
{
read(fd,&c,1);
n++;
write(fw,&c,1);
}
//3. 关闭
close(fd);
close(fw);
return 0;
}
执行结果