进程间通信---管道

进程间通信----(IPC)InterProcess Communication

一:管道

管道(包括无名管道和命名管道),通常指无名管道,是 UNIX 系统IPC最古老的形式。

[含义]:管道是一个进程的数据流到另一个进程的通道,即一个进程的数据的输出作为另一个进程的数据的输入,管道起到了桥梁的作用

比如:当我们输入: ls -l | cat test .其中ls和cat是两个进程,|代表管道,意思是执行ls -l进程,并将输出结果作为cat test进程的输入,cat进程将输入的结果打印在屏幕上:

[本质]:匿名管道之所以可以通信的本质在于,父进程fork子进程,父子进程各自拥有一个文件描述符表,但是两者的内容是一样的,既然内容一致,那么指向的就是同一个管道,即父子进程看到了同一份公共资源

1、特点:
  1. 它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。若要进行双向通信,需要两个管道

  2. 它只能用于具有共同祖先的进程之间的通信(也是父子进程或者兄弟进程之间)。

  3. 它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。

  4. 一般而言,进程退出,管道释放,管道通信依赖于文件系统,所以管道的生命周期随进程
  5. 一般而言,内核会对管道操作进行同步和互斥,保证读写顺序一致
  6. 管道的通信被称为面向字节流

2、管道的读写规则

当没有数据可读时,read调用阻塞,即进程暂停执行,一直等到有数据来到为止

当管道满的时候,write调用阻塞,直到有进程读走数据.

1)如果所有指向管道写端的文件描述符都关闭了(管道写端的引用计数为0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据被读取后,再次read会返回0,就像读到文件末尾一样。

2)如果有指向管道写端的文件描述符没关闭(管道写端的引用计数大于0),而持有管道写端的进程也没用向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。

3)如果所有指向管道读端的文件描述符都关闭了(管道读端的引用计数等于0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。

4)如果有指向管道读端的文件描述符没有关闭(管道读端的引用计数大于0),而持有管道读端的进程也没有从管道中读取数据,这是有进程向管道的写端写入数据,那么在管道被写满时,再次write会阻塞,直到管道中有空位置了才写入数据并返回。


2、原型:

1 #include <unistd.h>
2 int pipe(int fd[2]);    // 返回值:若成功返回0,失败返回-1

当一个管道建立时,它会创建两个文件描述符:fd[0]为读而打开,fd[1]为写而打开。如下图:

要关闭管道只需将这两个文件描述符关闭即可

3、例子

单个进程中的管道几乎没有任何用处。所以,通常调用 pipe 的进程接着调用 fork,这样就创建了父进程与子进程之间的 IPC 通道。如下图所示:

若要数据流从父进程流向子进程,则关闭父进程的读端(fd[0])与子进程的写端(fd[1]);反之,则可以使数据流从子进程流向父进程。

4.代码

1.创建管道

2.创建子进程

3.子进程写数据

4.父进程读数据

  1 #include<stdio.h>                                                                                                                                      
  2 #include<unistd.h>
  3 #include<errno.h>
  4 #include<string.h>
  5 #include<stdlib.h>
  6 int main(){
  7     int fd[2];
  8     if(pipe(fd)==-1){
  9      perror("pipe");
 10      return -1;
 11     }
 12     pid_t pid;
 13     pid=fork();
 14     if(pid==-1){
 15     perror("fork");
 16     }
 17     if(pid==0){
 18      close(fd[0]);
 19      write(fd[1],"hello",5);
 20      close(fd[1]);
 21      exit(-1);
 22     }
 23     if(pid>0){
 24       close(fd[1]);
 25       char buf[10]={0};
 26       read(fd[0],buf,10);
 27       printf("buf=%s\n",buf);
 28     }
 29     return 0;
 30 } 


吐舌头吐舌头以上我们介绍的是匿名管道,现在我们来看一下命名管道

我们会发现,匿名管道有一个限制就是只能用于具有共同祖先的进程,如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它就是我们经常提到的命名管道(命名管道是一种特殊的文件类型),命名管道之所以可以实现进程间通信在于通过同一个路径名而看到同一份资源,这份资源以FIFO的文件形式存在于文件系统中。FIFO总是按照先入先出的原则工作,第一个被写入的数据将首先从管道读出。

命名管道对应磁盘上的一个文件名,一旦建立起文件名与管道的关系,删掉文件是没有关系的

1,创建命名管道

命名管道可以在命令行上创建-----   $ mkfifo filename

命名管道也可以从程序里创建-------  int mkfifo(const char *filename,mode_t mode);

创建命名管道

int main(int argc,char *argv[]){
   mkfifo("p2",0644);
   return 0;
}

2,命名管道与匿名管道的区别

匿名管道由pipe函数创建并打开

命名管道由mkfifo函数创建,打开用open

一旦这些工作做好之后,它们具有相同的语义

3,命名管道实现服务器和客户端的通信

server_pipe.c

  1 #include<stdio.h>                                                                                                    
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 #include<unistd.h>
  6 #include<stdlib.h>
  7 int main(){
  8     //创建命名管道
  9   if(mkfifo("mypipe",0644)<0)
 10   {
 11      perror("mkfifo");
 12      exit(1);
 13   }
 14   int Rfd = open("mypipe",O_RDONLY);
 15   if(Rfd<0)
 16   { perror("mkfifo");
 17     exit(1);
 18   }
 19   char buf[1024];
 20   while(1){
 21    buf[0]=0;
 22    printf("please wait...\n");
 23    //服务器从文件即管道里读数据放入buf中
 24    ssize_t s = read(Rfd,buf,sizeof(buf)-1);
 25    if(s>0){
 26    buf[s-1]=0;
 27    printf("client say# %s\n",buf);
 28    }
 29    else if(s==0){
 30     printf("client quit,exit now!\n");
 31     exit(1);
 32    }
 33    else{                                                                                                             
 34      perror("read");
 35      exit(1);
 36    }
 37   }
 38  close(Rfd);
 39  return 0;
 40 }            

client_pipe.c

 
  1 #include<stdio.h>  
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 #include<unistd.h>
  6 #include<stdlib.h>
  7 #include<string.h>
  8 int main(){
  9 int Wfd = open("mypipe",O_WRONLY);
 10 if(Wfd<0)
 11 {
 12   perror("open");
 13   exit(1);
 14 }
 15 char buf[1024];
 16 while(1){
 17 buf[0]=0;
 18 printf("please enter# ");
 19 fflush(stdout);
 20 //从标准输入里读数据放到buf缓冲区中
 21 ssize_t s = read(0,buf,sizeof(buf)-1);
 22 if(s>0){
 23 buf[s]=0;
 24 //如果读到了就写入Wfd文件里
 25 write(Wfd,buf,strlen(buf));
 26 }
 27 else if(s<=0){
 28 perror("read");
 29 exit(1);
 30 }
 31 }
 32 close(Wfd);
 33 return 0;
 34 }                




基于SSM框架的智能家政保洁预约系统,是一个旨在提高家政保洁服务预约效率和管理水平的平台。该系统通过集成现代信息技术,为家政公司、家政服务人员和消费者提供了一个便捷的在线预约和管理系统。 系统的主要功能包括: 1. **用户管理**:允许消费者注册、登录,并管理他们的个人资料和预约历史。 2. **家政人员管理**:家政服务人员可以注册并更新自己的个人信息、服务类别和服务时间。 3. **服务预约**:消费者可以浏览不同的家政服务选项,选择合适的服务人员,并在线预约服务。 4. **订单管理**:系统支持订单的创建、跟踪和管理,包括订单的确认、完成和评价。 5. **评价系统**:消费者可以在家政服务完成后对服务进行评价,帮助提高服务质量和透明度。 6. **后台管理**:管理员可以管理用户、家政人员信息、服务类别、预约订单以及处理用户反馈。 系统采用Java语言开发,使用MySQL数据库进行数据存储,通过B/S架构实现用户与服务的在线交互。系统设计考虑了不同用户角色的需求,包括管理员、家政服务人员和普通用户,每个角色都有相应的权限和功能。此外,系统还采用了软件组件化、精化体系结构、分离逻辑和数据等方法,以便于未来的系统升级和维护。 智能家政保洁预约系统通过提供一个集中的平台,不仅方便了消费者的预约和管理,也为家政服务人员提供了一个展示和推广自己服务的机会。同时,系统的后台管理功能为家政公司提供了强大的数据支持和决策辅助,有助于提高服务质量和管理效率。该系统的设计与实现,标志着家政保洁服务向现代化和网络化的转型,为管理决策和控制提供保障,是行业发展中的重要里程碑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值