进程间通信----管道
来源:互联网 发布:axure mac安装教程 编辑:程序博客网 时间:2024/06/08 11:57
一,进程间通讯原理
每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程间交换数据,必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这个机制称为进程间通信(IPC)
二,进程间通信——管道
(一),匿名管道
匿名管道是一种最基本的IPC进制,由pipe函数创建:
#include <unistd.h>int pipe(int fd[2]);
pipe函数调用成功返回0,调用失败返回-1,参数为文件描述符,fd[0]指向管道读端,fd[1]指向管道写端,管道其实就像一个打开的文件可通过read(fd[0]);或write(fd[1])进行读写操作,
(一)验证匿名管道思路:
(1)父进程调用pipe开辟管道,得到两个文件描述符指向管道两端。
(2)父进程调用fork创建子进程,子进程两个文件描述符指向同一管道读写端。
(3)父进程关闭写端,子进程关闭读端,子进程往管道里写,父进程从管道里读,实现进程通信。
验证代码:
int main() 5 { 6 int fds[2];//fds[0]为管道读取端;fds[1]为管道写入端; 7 if (pipe(fds)<0) //管道创建失败返回-1; 8 { 9 perror("pipe"); 10 return 1; 11 } 12 //管道创建成功返回0; 13 //实现进程间通讯;父子进程间通讯; 14 pid_t id = fork(); 15 if(id == 0) 16 { 17 //child->write 18 close(fds[0]);//fds[1]->write point 19 const char* msg = "hello father,i am child,hello pipe!"; 20 while(1) 21 { 22 write(fds[1],msg,strlen(msg)); 23 sleep(1); 24 } 25 } 26 else //father->read; 27 { 28 close(fds[1]);//fds[0]->read point 29 char buf[1024]; 30 while(1) 31 { 32 ssize_t s = read(fds[0],buf,sizeof(buf)-1); 33 if(s >0) 34 { 35 buf[s-1] = 0; 36 printf("ywx->#%s\n",buf); 37 } 38 } 39 } 40 return 0; 41 }
可以看出,父进程可以输出子进程写的内容。
(二),匿名管道特点
(1)常用于具有血缘关系的进程通信,如父子进程
(2)单向通信
(3)基于字节流
(4)生命周期随进程
(5)同步
(三),几种特殊情况(大家自行验证)
(1)读端不读,写端一直写,则写满管道,写端则阻塞。
(2)写端不写,读端一直读,则读空管道,读端则阻塞。
(3)读端一直读,写端被关闭,则读到文件结尾就停止。
(4)写端一直写,读端被关闭,则写端会被操作系统终止。
(二),命名管道
命名管道克服了只有血缘关系之间才可以通信,任意两个进程都可以进行通信。
命名管道有两种方式创建。一是在shell下交互地建立一个命名管道,二是程序中使用系统函数建立命名管道,shell方式下可以使用mknod或mkfifo函数。如下
#include <sys/type.h>#include <sys/stat.h>int mknod(const char* path,mode_t mod,dev_t dev);int mkfifo(const char* path,mode_t mod);
两个函数调用成功返回0,失败返回-1,
第一个参数path 为创建命名管道的全路径名(文件名),mod为创建的命名管道的权限;dev为设备值,取决文件创建种类,只在创建设备文件时才会用到。
mknod函数创建命名管道
umask(0);if (mknod("/tmp/fifo",S_IFIFO|0666)==-1){ perror("mknod error");}exit(1);
mkfifo函数创建命名管道
umask(0);if (mkfifo("/tmp/fifo",S_IFIFO|0666)==-1){ perror("mkfifo error");}exit(1);
“S_IIFIO|0666”指明创建一个命名管道取权限0666,(注意umask对文件权限的影响),命名管道创建成功后,必须以open()打开,这和匿名管道不同,这点是因为命名管道是一个存在于硬盘的文件,而匿名管道是存在内存中的特殊文件。注意Open打开命名管道进程可能会阻塞。同时以读写方式打开(O_RDWR)打开,不会阻塞,以只读方式打开(O_RDONLY),则调用open函数的进程将会被阻塞知道有写方式打开管道,同时以写方式(O_WRITE)打开也会阻塞直到有读写方式打开管道。
(一),验证命名管道
思路:创建命名管道,进行两个进程之间通信
代码如下:
server.c
#include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <unistd.h> 5 #include <fcntl.h> 6 #include <string.h> 7 #define _PATH_ "./mypipe" 8 #define _SIZE_ 1024 9 int main() 10 { 11 int fd = open(_PATH_,O_WRONLY); 12 if(fd <0) 13 { 14 printf("open file error!\n"); 15 return 1; 16 } 17 char buf[_SIZE_]; 18 while(1) 19 { 20 printf("please Enter#"); 21 fflush(stdout); 22 ssize_t s = read(0,buf,sizeof(buf)-1); 23 if(s>0) 24 { 25 buf[s-1] = 0; 26 write(fd,buf,strlen(buf)); 27 28 } 29 } 30 close(fd); 31 return 0; 32 } 33
client.c
#include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <string.h> 5 #include <fcntl.h> 6 #include <unistd.h> 7 int main() 8 { 9 umask(0); 10 if(mkfifo("./mypipe",0666|S_IFIFO)<0) 11 { 12 perror("mkfifo"); 13 return 1; 14 } 15 16 int fd = open("./mypipe",O_RDONLY); 17 if(fd<0) 18 { 19 perror("open"); 20 return 2; 21 } 22 char buf[1024]; 23 memset(buf,'\0',sizeof(buf)); 24 while(1) 25 { 26 ssize_t s = read(fd,buf,sizeof(buf)-1); 27 if (s >0) 28 { 29 buf[s] = 0; 30 printf("server say# %s\n",buf); 31 } 32 else if(s== 0) 33 { 34 printf("server quit! client begin quit!\n "); 35 break; 36 } 37 } 38 close(fd); 39 return 0; 40 } 41
运行结果如下:
这样就实现了进程间通信了。
(二,)命名管道特点
(1)任意两个进程之间都可以通信,无血缘限制。
(2)同步
(3)基于字节流
(4)生命周期随进程
(5)单向通信
- 进程间管道通信
- 进程间通信: 管道
- 进程间通信--管道
- 进程间通信----管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信----管道
- 进程间通信----管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信-管道
- 进程间管道通信
- 进程间管道通信
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信-管道
- 树莓派从零开始学习记录
- java Map 接口
- Android透明状态栏或者渐变色状态栏
- IO
- Sqlserver_数据库间导数据
- 进程间通信----管道
- Atom 常用快捷键
- 使用IO流对文件进行编写功能
- SpringMvc4.x基础(一):项目快速搭建
- Android安卓4.0以下,fastclick触发两次?
- Glide加载图片时转换为圆形、圆角、毛玻璃等图片效果
- RF中中文乱码解决方案
- 微信开发-关于分享朋友&朋友圈以及录音功能
- Mac QQ 防撤回------------------简单实现防女朋友撤回消息(好吧程序员哪有女朋友,我瞎说的....)