进程间通信的通信机制

进程间通信主要分为两个大类:

1、Unix继承的通信方式:信号、管道

2、system V IPC对象:共享内存、消息队列、信号灯集、套接字(网络编程使用)

目录

一、管道

1、无名管道

2、有名管道

二、信号

1、定时器

2、暂停

3、捕获信号

三、共享内存

实现流程

1、key值的获取

2、创建或者打开共享内存——shmget

3、映射共享内存——shmat

4、访问共享内存

5、取消映射——shmdt

6、删除共享内存——shmctl

四、消息队列

实现流程

1、创建、打开消息队列——msgget

2、发送消息——msgsnd

3、接收消息——msgrcv

4、操作消息队列——msgctl

五、信号灯集

实现流程:

1、获取信号灯——semget

2、设置信号灯初值(或其它操作:比如删除)——semctl

3、实现PV操作——semop

六、套接字


一、管道

1、无名管道

文件系统中不可见(不存在-p文件)

特点:
    1、创建之后在文件系统中不可见
    2、以半双工的方式进行通信
    3、拥有固定的读端和写段
    4、只能用于具有亲缘关系的进程间通信

读特性:
    写端存在:
            管道有数据:返回读到的字节数
            管道无数据:程序阻塞
    
    写段不存在:
            管道有数据:返回读到的字节数
            管道无数据:返回0
            
写特性:
    读端存在:
            管道有空间:返回写入的字节数
            管道无空间:程序阻塞,直到有空间为止
            
    读端不存在:
            无论管道是否有空间,管道破裂,管道破裂进程终止

#include

int pipe(int pipefd[2]);

参数:
    pipefd:存放无名管道读端和写端的数组首地址
    
    pipefd[0]——读端
    pipefd[1]——写端

返回值:
    成功返回0,失败返回-1

2、有名管道

文件系统中可见(存在-p文件)

有名管道创建之后会在文件系统中以管道文件的形式存在

有名管道可以用于任意两个进程间通信,没有固定的读写端

#include
#include

int mkfifo(const char *pathname, mode_t mode);

参数:
    pathname:创建管道文件的文件名
    mode:创建管道文件的权限


返回值:
    成功返回0,失败返回1

二、信号

信号:是中断在软件层次上的一种模拟

信号的处理方式:
    默认处理:
    忽略处理:
    捕获信号:

常用信号指令:

kill

1、定时器

        定时时间到时,当前进程会接收到编号为14的信号——SIGARLM
一个进程中最多只能存在一个定时器

相关函数:——alarm

#include

unsigned int alarm(unsigned int seconds);

参数:
    second:定时秒数
    
返回值:
    成功返回0或者上一个定时器剩余的时间

2、暂停

#include

int pause(void);

功能:阻塞在当前位置,等待定时结束

3、捕获信号

#include

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

参数:
    signum:指定信号
    hand1er:信号处理函数
            SIG_IGN:选择以忽略方式处理指定信号
            SIG_DEF:选择以默认方式处理指定信号

父进程回收子进程

三、共享内存

是所有进程间通信效率最高的一种通信机制(将需要的内核层数据映射到用户层实现的)

实现流程

1、key值的获取

#include
#include      

key_t ftok(const char *pathname, int proj_id);

参数:
    pathname:任意路径
    proj_id:任意字符

返回值:
    成功返回key值,失败返回-1

2、创建或者打开共享内存——shmget

#include
#include

int shmget(key_t key, size_t size, int shmflg);

参数:
    key:通过ftok得到的key或者使用IPC_PRIVATE(创建私有共享内存)
    size:共享内存的大小
    shmflg:创建共享内存权限,一般填 0664 | IPC_CREAT

返回值:
    成功返回得到共享内存ID号,失败返回-1

3、映射共享内存——shmat

#include
#include

void *shmat(int shmid, const void *shmaddr, int shmflg);

参数:
    shmid:共享内存ID
    shmaddr:映射地址,NULL表示系统自动分配
    shmflg:
            SHM_REDONLY —— 只读
            0 —— 读写

返回值:
    成功返回映射地址,失败返回(void *)-1

4、访问共享内存

访问shmat返回的地址空间即可

5、取消映射——shmdt

#include
#include

int shmdt(const void *shmaddr);

参数:
    shmaddr:表示要取消映射的地址

返回值:
    成功返回0,失败返回-1

6、删除共享内存——shmctl

#include
#include

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

参数:
    shmid:共享内存id号
    cmd:操作共享内存的命令
            IPC_STAT:获取共享内存的信息,需要用到第三个参数
            IPC_SET:设置共享内存信息
            IPC_RMID:删除共享内存,第三个参数填空(映射全部取消之后才会删除)

返回值:
    成功返回0,失败返回-1

四、消息队列

        多个进程可同时向一个消息队列发送消息,也可以同时从一个消息队列中接收消息。发送进程把消息发送到队列尾部,接受进程从消息队列头部读取消息,消息一旦被读出就从队列中删除。

实现流程

1、创建、打开消息队列——msgget

#include
#include
#include

int msgget(key_t key, int msgflg);

参数:
    key:通过ftok创建的key值或者使用IPC_PRIVATE创建私有的消息队列
    shmflg:创建共享内存权限,一般填 0664 | IPC_CREAT
    

返回值:
    成功返回消息队列id号,失败返回-1
    
例:
    int msgid = msgget(IPC_PRIVATE, 0664)

2、发送消息——msgsnd

#include
#include
#include

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

参数:
    msqid:消息队列id
    msgp:跟发送消息相关的结构体的首地址
    msgsz:消息结构体中正文内容的大小
    msgflg:
        0——表示以阻塞方式发送内容
        IPC_NOWAIT——以非阻塞方式发送内容

返回值:
    成功返回0,失败返回-1
    
msgp用法:


#define LEN (sizeof(MSG) - sizeof(long))

typedef struct msgbuf
{
    long mtype;
    char mtext[N];
}MSG;

    MSG msg;
    char buf[N] = {0};
    msg.mtype = 100;
    
    fgets(buf, N, stdin);
    strcpy(msg.mtest, buf)
    
    msgsnd(msgid, &msg, LEN, 0);

3、接收消息——msgrcv

#include
#include
#include

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

参数:
    msqid:消息队列id
    msgp:接收消息相关的结构体的首地址
    msgsz:消息结构体中正文内容的大小
    msgflg:


        0——表示以阻塞方式接收内容
        IPC_NOWAIT——以非阻塞方式接收内容

4、操作消息队列——msgctl

#include
#include
#include

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

cmd:操作共享内存的命令
            IPC_STAT:获取共享内存的信息,需要用到第三个参数
            IPC_SET:设置共享内存信息
            IPC_RMID:删除共享内存,第三个参数填空(映射全部取消之后才会删除)

五、信号灯集

         信号灯与其他进程间通信方式不大相同,它主要提供对进程间共享资源访问控制机制。相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源,同时,进程也可以修改该标志。除了用于访问控制外,还可用于进程同步。

实现流程:

1、获取信号灯——semget

#include
#include
#include

int semget(key_t key, int nsems, int semflg);

参数:
    key:产生信号灯id需要使用的键值,可以用IPC_PRIVATE或者ftok             来获取
    nsems:信号灯集中包含信号的个数
    semflg:标志位 设置信号灯权限    例如:创建需要添加IPC_CREAT标志位
    
返回值:
    成功返回信号灯ID号,失败返回-1

2、设置信号灯初值(或其它操作:比如删除)——semctl

#include
#include
#include

int semctl(int semid, int semnum, int cmd, ...);

参数:
    semid:信号灯标识id
    semnum:要控制的信号灯编号(从0开始)
    cmd:控制命令    
            IPC_RMID:删除
            IPC_SET:设置信号灯相关属性
    
    ...:可变参数,如果第三个参数是IPC_RMID则第四个参数可以不传
        如果第三个参数是IPC_SET则需要传递第四个参数
        参数类型可以是一个共用体:
        
        union semun 
        {
               int val;   
               struct semid_ds *buf;   
               unsigned short  *array;  
               struct seminfo  *__buf; 
        };

3、实现PV操作——semop

#include
#include
#include

int semop(int semid, struct sembuf *sops, size_t nsops);

参数:
        struct sembuf
           {
                   unsigned short  sem_num;  
                   short           sem_op
                  short           sem_flg;  
           }


           sem_num:信号灯编号
           sem_op:
                    1 :表示V操作(释放资源)
                   -1 :表示P操作(申请资源)  
           sem_flg:
                   通常为0表示阻塞等待
                   
           nsops:表示要控制多少个灯
                   

六、套接字

主要用于网络编程中,也可以用于进程间通信

你可能感兴趣的:(嵌入式,IO进线程,C++,开发语言,linux,unix,网络协议,网络)