进程间通信

举报
看,未来 发表于 2020/12/30 00:57:34 2020/12/30
【摘要】 目录 4.1 pipe管道 4.2 FIFO有名管道 4.3 内存共享映射 4.4 Unix Domain Socket 4.1 pipe管道 什么是管道? 可以理解为内存中的一个缓冲区,用于将某个进程的数据流导入,由某一个进程导出,实现通信。 再通俗的说,看图: 晓得了吧 这个pipe管道可以理解为匿名管道,是基于文件描述符的通信方式...

目录

4.1 pipe管道

4.2 FIFO有名管道

4.3 内存共享映射

4.4 Unix Domain Socket





4.1 pipe管道

什么是管道?
可以理解为内存中的一个缓冲区,用于将某个进程的数据流导入,由某一个进程导出,实现通信。
再通俗的说,看图:
在这里插入图片描述

晓得了吧

这个pipe管道可以理解为匿名管道,是基于文件描述符的通信方式,使用时两个进程必须有血缘关系,父子进程之间的通信。

放码出来:

#include<unistd.h>

int pipe(int filedes[2]);

//成功返回0,失败返回-1


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

pipe函数在内存中开辟一块缓冲区,由filedes参数传出给用户程序使用的两个文件描述符。
【0】为读端使用,【1】为写端使用。

在这里插入图片描述
行了,还是来段代码吧

主要就是三部曲,看我标注出来

#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{ int fds[2]; if(pipe(fds) < 0)	//父进程调用pipe创建管道,得到两个文件描述符指向管道的两端(1) { perror("pipe"); return 1; } char buf[1024]; printf("Please enter:"); fflush(stdout); ssize_t s =  read(0,buf,sizeof(buf)-1); if(s > 0) { buf[s] = 0; } pid_t pid = fork();	//父进程克隆出子进程,子进程同样有两个文件描述符指向同一管道(2) if(pid == 0) { //子进程只写,关闭读端(3.1) close(fds[0]); while(1) { sleep(1); write(fds[1],buf,strlen(buf));//将buf的内容写入管道(3.3) } } else { //父进程只读,关闭写端(3.2) close(fds[1]); char buf1[1024]; while(1) { ssize_t s = read(fds[0],buf1,sizeof(buf1)-1);//从管道里读数据,放入buf(3.3) //形成一个消息循环 if(s > 0) { buf1[s-1] = 0; printf("client->farther:%s\n",buf1); } } }
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

使用匿名管道有一些限制:

1、只能够进行单向通信
2、只能够用于有血缘关系(父子,兄弟,爷孙)的进程之间,多常用于父子之间
3、管道内部自带同步机制:子进程写一条,父进程读一条
4、管道的生命周期为随进程,进程结束管道就没了
5、管道内没有数据时,读端(read)发生阻塞,等待有效数据进行读取
6、管道容量被数据填满时,写端(write)发生阻塞,等待进程将数据读走再进行写入

4.2FIFO有名管道

创建一个有名管道,解决无血缘关系的进程之间的通信 :FIFO

这个有两个办法来创建:

//方法1:
mkfifo 管道名

方法2#include<sys/types.h>
#include<sys/stat.h>

int mkfifo(const char *pathname,mode_t mode);
//参数释义:
/*
	filename:创建的有名管道的全路径名 mode:创建的命名管道的模式,指明其存取权限
*/ 
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

还是先上个实例:(以下为伪代码,主要为管道部分)

write.c

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

//读取文件,将文件内容写入管道
int main()
{ mkfifo("tp",0644);//创建一个管道文件 int  infd = open("123",O_RDONLY);//打开一个文件 int  outfd = open("tp",O_WRONLY);//打开管道文件,将123文件的内容写入管道文件   char buf[1024];//用于存放文件内容 ssize_t s; while( (s = read(infd,buf,sizeof(buf))) >0) { write(outfd,buf,s);//将123文件的内容写入管道文件  } close(infd); close(outfd);//关闭有名管道文件描述符

}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

read.c

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

//从管道文件里面读取内容,并将内容写入另一个文件中
int main()
{ int infd = open("abc.bak",O_CREAT | O_WRONLY | O_TRUNC,0644);//创建一个新的文件 //将从管道读取的内容写入到新的文件中 int outfd = open("tp",O_RDONLY);//打开管道文件 char buf[1024];//临时数组 ssize_t s; while( (s = read(outfd,buf,sizeof(buf))) > 0) //从管道中读取数据 { write(infd,buf,s); } close(infd); close(outfd); //关闭有名管道 return 0;
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

有名管道也有·自己的独特之处:

  1. 可以进行不相干进程间的通信
  2. 命名管道是一个文件,对于文件的相关操作对其同样适用
  3. 对于管道文件,当前进程操作为只读时,则进行阻塞,直至有进程对其写入数据
  4. 对于管道文件,当前进程操作为只写时,则进行阻塞,直至有进程从管道中读取数据

  
 

    5.FIFO可以一个读端,多个写端。也可以一个写端,多个读端。
    6.FIFO支持双向通信

    4.3 内存共享映射

    起的一个好名字,mmap/munmap

    mmap可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存地址,对文件的读写可以直接用指针来做而不需要read/write

    共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。

    哎,手指都要肿了,放码吧

    //mmap()系统调用形式如下:
    
    void* mmap ( void * addr , size_t len , int prot , int flags , int fd , off_t offset )
    
    
      
     
    • 1
    • 2
    • 3
    • 4

    参数释义
    addr指定文件应被映射到进程空间的起始地址,一般被指定一个空指针,反正你也找不到,此时选择起始地址的任务留给内核来完成。
    len是映射到调用进程地址空间的字节数,它从被映射文件开头offset个字节开始算起。
    prot 参数指定共享内存的访问权限。可取如下几个值的或:
    PROT_READ(可读) , PROT_WRITE (可写), PROT_EXEC (可执行), PROT_NONE(不可访问)。
    flags由以下几个常值指定:MAP_SHARED , MAP_PRIVATE , MAP_FIXED,
    其中,MAP_SHARED , MAP_PRIVATE必选其一,而MAP_FIXED则不推荐使用。
    fd为即将映射到进程空间的文件描述字,一般由open()返回
    offset参数一般设为0,表示从文件头开始映射。(必须是页大小的整数倍(4K))
    函数的返回值为最后文件映射到进程空间的地址,进程可直接操作起始地址为该值的有效地址。

    //系统调用munmap()
    
    int munmap( void * addr, size_t len )
    
    /*该调用在进程地址空间中解除一个映射关系,addr是调用mmap()时返回的地址,len是映射区的大小。当映射关系解除后,对原来映射地址的访问将导致段错误发生。*/
    
    
      
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    //系统调用msync()
    
    int msync ( void * addr , size_t len, int flags)
    /*一般说来,进程在映射空间的对共享内容的改变并不直接写回到磁盘文件中,往往在调用munmap()后才执行该操作。可以通过调用msync()实现磁盘上文件内容与共享内存区的内容一致。*/
    
      
     
    • 1
    • 2
    • 3
    • 4

    好,看范例

    #include <sys/mman.h>;
    #include <sys/types.h>;
    #include <fcntl.h>;
    #include <unistd.h>;
    typedef struct
    { char name[4]; int  age;
    }people;
    
    main(int argc, char** argv) // map a normal file as shared mem:
    { int fd,i; people *p_map; char temp; fd=open(argv[1],O_CREAT|O_RDWR|O_TRUNC,0777); lseek(fd,sizeof(people)*5-1,SEEK_SET); write(fd,"",1); p_map = (people*) mmap( NULL,sizeof(people)*10,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0 ); close( fd ); temp = 'a'; //直接使用这种写入方式 for(i=0; i<10; i++) { temp += 1; memcpy( ( *(p_map+i) ).name, &temp,2 ); ( *(p_map+i) ).age = 20+i; } printf(" initialize over /n ")sleep(10); munmap( p_map, sizeof(people)*10 ); printf( "umap ok /n" );
    }
    
      
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    文章来源: lion-wu.blog.csdn.net,作者:看,未来,版权归原作者所有,如需转载,请联系作者。

    原文链接:lion-wu.blog.csdn.net/article/details/103940038

    【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
    • 点赞
    • 收藏
    • 关注作者

    评论(0

    0/1000
    抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。