Linux进程间通信


待我慢慢总结..........

参考文章:

[1] 进程间的五种通信方式介绍

[2] 《嵌入式Linux开发教程(上册)》


进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。

IPC的方式通常有管道(包括无名管道和命名管道)共享存储消息队列信号量、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC。

1. 管道

管道是一个进程连接数据流到另外一个进程的通道,它通常被用作把一个进程的输出通过管道连接到拎一个进程的输入。管道分为匿名管道命名管道(FIFO:先进先出)。

1.1 匿名管道(无名管道)

特点:

  • 匿名管道是一种无法在文件系统以任何方式看到的半双工管道
  • 匿名管道用于具有亲缘关系的进程之间的通信(父子进程或者兄弟进程之间)
  • 它可以看成一种特殊的文件,但是不属于任何文件系统,只存在于内存之中
  • 对匿名管道可以使用普通的read、write函数

pipe()函数可以用来创建一条匿名管道,它的原型如下:

#include <unistd.h>

int pipe(int pipefd[2]);

//pipefd[0] : 读端read
//pipefd[1] : 写端write

函数成功返回0,否则返回-1。

单个进程中匿名管道的使用:

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

 

fork进程之间的匿名管道通信:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
/* 父进程向管道写入字符串hello son                 :关闭读fd[0] : close
 * 子进程读取管道,并且打印出所读取的字符串:关闭写fd[1] : close
 * */
int main(){
        pid_t proc;
        int fd[2];
        char buff[20];
        if(pipe(fd) < 0)
                printf("pipe create error!\n");
        proc = fork();
        if(proc < 0)
                printf("create error!\n");
        else if(proc > 0){
                sleep(1);
                close(fd[0]);
                //sleep(1);
                write(fd[1],"hello,son!\n",12);
                printf("this is father!\n");
                wait(0);
        }

        else{
                //关闭写fd
                sleep(1);
                close(fd[1]);
                //sleep(1);
                read(fd[0],buff,20);
                printf("this is son!\n");
                printf("i get the string = %s\n",buff);

        }

}

输出:

1.2 命名管道(FIFO:先进先出)

命名管道也被成为FIFO文件。

特点:

  • 使同一主机的所有进程都可以相互通信。
  • FIFO是一种特殊的文件类型,他在文件系统中以文件名的形式存在,在stat结构中,mode指明一个文件结点是不是命名管道

建立匿名管道

mkfifo()函数用来创建一个命名管道,它的原型如下:

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

int mkfifo(char * pathname, mode_t mode);
  • mkfifo()创建了一个真实存在于文件系统中的命名管道,参数pathname制定了文件名,参数mode制定了文件的读写权限。函数成功返回0,否则返回-1并设置error
  • mkfifo()创建命名管道以后,需要通过命名管道通信的进程需要打开该管道文件,然后通过read(write)函数像操作普通文件一样进行通信。

删除命名管道
如果要删除一个使用完的FIFO文件,则需要unlink命令,示例如下:
Linux也提供了一个相应的unlink函数:Linux常用C函数
 

2. 共享存储

共享内存就是两个(或多个)进程共同占有一段内存空间,这些进程可以是有亲缘关系的进程,也可以是完全不相关的进程。同一块物理内存空间被映射到两个进程,两个进程都可以访问这段共享空间从而实现了进程间通信。但是值得注意的是:Linux的共享内存通信只提供了数据交换功能,并没有提供同步机制,需要使用其它机制来同步不同进程对共享内存的读写操作(如信号量)。

共享内存区设计四个主要步骤:

  1. 指定一个名字参数调用shm_open,以创建一个新的共享内存区对象(或打开一个已经存在的共享内存区对象);
  2. 调用mmap()把这个共享内存区映射到调用进程的地址空间
  3. 调用munmap()取消共享内存映射
  4. 调用shm_unlink()函数函数共享内存段

2.1 创建或者打开共享存储shm_open

函数原型:

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

int shm_open(const char* name, int oflag, mode_t mode);

函数成功返回创建或打开的内存共享描述符,与文件描述符作用相同,否则返回-1

参数name:指定创建的共享内存名称,其他进程可以根据这个名称来打开共享内存

参数flag可以为以下值:

  • O_RDONLY:共享内存以只读方式打开
  • O_RDWR:共享内存以可读可写的方式打开
  • O_CREAT:共享内存不存在时才创建
  • O_EXCL:如果指定了O_CREAT,但共享内存已经存在时返回错误信息
  • O_TRUNC:如果共享内存已经存在,则将其大小设置为0

参数mode只有指定O_CREAT才有效,指出共享内存的权限,与open()函数类似

注意:新创建或者打开的共享内存大小默认为0,需要设置大小才能使用。

2.2 设置共享内存大小

使用ftruncate()函数来调整文件或者共享内存的大小,原型如下:

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

int ftruncate(int fd, off_t length);

函数成功返回0,失败返回-1

参数fd:需要调整的共享内存或者文件。

参数length:需要调整的大小(单位是字节)。

2.3 映射共享内存

创建共享内存之后,需要将这块内存区映射到调用进程的地址空间中,可以使用mmap()来完成,mmap()原型如下:

#include <sys/mman.h>

void * mmap(void *addr, size_t length, int prot, int flag, int fd, off_t offset);

函数成功返回映射后指向共享内存的虚拟地址,失败则返回MAP_FAILED值。

参数如下:

  • addr:指向映射存储区的虚拟地址,通常将其设置为NULL,这表示由系统选择该映射区的起始地址
  • len:映射的字节数
  • port:对映射存取区的保护要求,对映射存储区的保护要求不能超过文件open模式的访问权限。他可以使用一下标志或值:
    • PORT_READ:映射区可读;
    • PORT_WRITE:映射区可写;
    • PORT_EXEC:映射区可执行;
    • PORT_NONE:映射区不可访问
  • flag:映射标志位,可以为以下标志或值
    • MAP_FIXED:返回值必须等于addr,不利于可移植性,故不推荐使用;
    • MAP_SHARED:对进程对同一个文件的映射是共享的,一个京城对映射的内存做了修改,另一个进程也会看到这个变化;
    • MAP_PRICATE:多进程对同一个映射区不是共享的,一个进程对映射的内存进行了修改,另外一个进程看不到这个变化;
  • fd:要被映射的文件描述符或者共享内存的描述符
  • offset:要映射字节在文件中的起始偏移量。

2.4 取消共享内存映射

在已经建立的共享内存映射,可以使用munmap()函数来取消。munmap()函数原型如下:

#include <sys/mman.h>

int munmap(coid *addr,size_t length);

函数成功返回0,否则返回-1.

  • addr:munmap()函数的返回地址;
  • length:映射的字节数

取消映射后在对映射地址对象访问会导致调用进程收到SIGSEGC信号。

2.5 删除共享内存

当使用完共享内存后,需要将其删除以释放系统资源,可以通过shm_unlink()函数完成,其原型如下:

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

int shm_unlink(const char * name);

函数成功返回0,否则返回-1.

参数name为共享内存的名字。

2.6 实例

 

3. 消息队列

 

4. 信号量

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值