Linux进程通信

进程间通信:
基本概念:
什么是进程间通信:
是指两个或者多个进程之间交互数据的过程,因为进程之间是相互独立的,为了能够让多个进程协同工作必须交互数据
进程间通信的分类:
简单的进程间通信:信号、文件、环境变量、命令行参数
传统的进程间通信:管道文件
XSI进程间通信: 共享内存、消息队列、信号量
网络进程间通信: Socket套接字

传统进程间通信:
管道是UNIX最古老的进程间通信方式,古老意味着所有系统都支持,早期的管道都是半双工,现在有些系统的管道是全双工(但是也要假定管道是半双工来实现)
管道就是一种特殊的文件,它的数据在文件中是流动的,读取之后就会消失,如果文件中没有数据可以读取则会阻塞

有名管道:  基于有文件名的管道文件的通信
           编程模型
    进程A           进程B
  创建管道           ...
  打开管道         打开管道
  写数据           读数据
  关闭管道         关闭管道
  删除管道           ...

    创建管道文件:
        1、命令 mkfifo file
        2、函数:
            int mkfifo(const char *pathname, mode_t mode);
            功能:创建管道文件
            pathname:管道文件路径
            mode:管道文件权限
        3、标准库函数
            FILE* popen(const char *command, const char *type);
            功能:打开或创建管道文件
            command:可执行文件名
            type:
                r  文件指针链接到可执行文件的标准输出 
                w  文件指针链接到可执行文件的标准输入

            int pclose(FILE *stream);
            功能:关闭管道文件
            注意:关闭管道文件的专用函数,一定不能与fclose混用

匿名管道:
    注意:只适合通过fork函数创建的父子进程之间使用
    int pipe(int pipefd[2]);
    功能:创建一个匿名管道文件,获取管道文件的读权限fd、写权限fd
    pipefd:用于存储管道文件的fd的数组
        pipefd[0]:用于读
        pipefd[1]:用于写

    编程模型
    父进程                  子进程
    创建获取一对fd
    创建子进程             拷贝一对fd
    关闭读                   关闭写 
    写数据                   读数据
    关闭写                   关闭读

XSI进程间通信:
X/open 公司执行的用于进程间通信的系统接口
XSI进程间通信都需要借助系统内核,需要创建内核对象,内核对象以整数形式返回给用户,相当于文件描述符,也叫做IPC标识符

文件的创建、打开需要文件名,IPC内核对象的创建也需要借助IPC键值(整数),必须要确保IPC键值独一无二

key_t ftok(const char *pathname, int proj_id);
功能:计算出一个独一无二的IPC键值
pathname:项目路径,不是依赖字符计算的,而是依赖路径的位置,如果提供的是假的路径,可能会计算出相同的IPC键值
proj_id:项目编号
返回值:计算出来的

共享内存:
基本特点:
两个或者多个进程之间共享一块由内核负责管理维护的内存,该内存可以与进程的虚拟内存空间进行映射
优点:不需要复制信息,是最快的一种IPC机制
缺点:需要考虑同步访问问题

int shmget(key_t key, size_t size, int shmflg);
功能:创建\获取共享内存
key:由进程提供的独一无二的IPC键值
size:共享内存的大小,获取共享内存时此参数无意义,一般设置为0
shmflg:
    IPC_CREAT   创建共享内存
    IPC_EXCL    共享内存已经存在时返回错误
    获取时赋值 0 
    mode_flags:创建共享内存时需要提供权限
返回值:IPC标识符,错误返回-1

void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:虚拟内存与共享内存进行映射
shmid:IPC标识符,shmget的返回值
shmaddr:想要映射的虚拟内存地址,给NULL系统会自动操作
shmflg:
    SHM_RDONLY:以只读方式访问共享内存
返回值:与共享内存映射后的虚拟内存的首地址,失败返回 (void *)-1

int shmdt(const void *shmaddr);
功能:取消映射
shmaddr:映射过的虚拟内存首地址

int shmctl(int shmid, int cmd, struct shmid_ds *buf); 
功能:删除/控制共享内存
shmid:IPC标识符
cmd:
    IPC_STAT    获取共享内存属性    则buf为输出型参数
    IPC_SET     设置共享内存属性    则buf为输入型参数
    IPC_RMID    删除共享内存        NULL
buf:
struct shmid_ds {
    struct ipc_perm shm_perm;    //所有者的相关信息
    size_t          shm_segsz;   //共享内存字节数
    time_t          shm_atime;   //最后映射时间
    time_t          shm_dtime;   //最后取消映射时间
    time_t          shm_ctime;   //最后改变时间
    pid_t           shm_cpid;    //创建者进程号
    pid_t           shm_lpid;    //最后映射\取消映射的进程号
    shmatt_t        shm_nattch;  //当前映射次数
    ...
};
struct ipc_perm {
    key_t          __key;    // 创建共享内存的PIC兼职
    uid_t          uid;      //当前使用共享内存的用户ID
    gid_t          gid;      //当前使用共享内存的用户组ID
    uid_t          cuid;     //创建共享内存的用户ID
    gid_t          cgid;     //创建共享内存的用户组ID
    unsigned short mode;     //共享内存权限
    unsigned short __seq;    //共享内存的序列号
};

编程模型
进程A                   进程B
创建共享内存           获取共享内存
映射共享内存           映射共享内存
写数据后通知读         接受读通知后读数据
接受读通知后读数据     写数据后通知读
取消映射               取消映射
删除共享内存

消息队列:
基本特点:是由内核管理维护的数据链表,通过消息类型来收发数据

int msgget(key_t key, int msgflg);
功能:创建/获取消息队列
key:IPC键值
msgflg:
    IPC_CREAT   创建消息队列
    IPC_EXCL    如果消息队列已存在则会返回错误
    如果获取消息队列 直接给0
    如果是创建消息队列,记得提供权限mode
返回值:成功返回IPC标识符,错误返回-1

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgfl);
功能:向消息队列发送数据
msqid:IPC标识符
msgp:要发送的消息的首地址
    struct msgbuf {
        long mtype;       // 消息类型
        char mtext[n];    // 数据
       };
msgsz: 数据的字节数,不包含消息类型
msgfl:
    阻塞一般写0
    IPC_NOWAIT  当消息队列满时,不等待立即返回

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
功能:从消息队列中读取数据
msqid:IPC标识符
msgp:存储数据的首地址
msgsz:结构体中数据的最大字节数
msgtyp:消息类型
    0   读取消息队列第一条消息
    >0  读取消息队列中消息类型等于msgtyp的消息
    <0  读取消息类型小于abs(msgtyp)消息,如果多个则读取最小的消息
msgflg:
    IPC_NOWAIT 当消息队列中没有匹配的消息类型时,立即返回
    MSG_EXCEPT  如果msgtyp>0,则读取第一个消息类型不是msgtyp的消息
    MSG_NOERROR 如果包含此标志,则读取msgsz个字节;如果不包含此标志,消息实际长度>msgsz,则会返回错误而不读取数据。
返回值:返回成功读取到的字节数

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:删除/获取消息队列的属性
msqid:IPC标识符
cmd:
    IPC_STAT    获取消息队列的属性
    IPC_SET     设置消息队列的属性
    IPC_RMID    删除消息队列
buf:
struct msqid_ds {
    struct ipc_perm msg_perm;     // 属主消息
    time_t          msg_stime;    // 最后发送时间
    time_t          msg_rtime;    // 最后接收时间
    time_t          msg_ctime;    // 最后修改时间
    unsigned long   __msg_cbytes; // 当前消息队列的字节数
    msgqnum_t       msg_qnum;     // 当前消息队列的消息数
    msglen_t        msg_qbytes;   // 队列中最大消息的字节数
    pid_t           msg_lspid;    // 最后发送者的PID
    pid_t           msg_lrpid;    // 最后接收者的PID
   };

编程模型:
进程A                   进程B
创建消息队列            获取消息队列
发送消息                接收消息
接收消息                发送消息
删除消息队列

信号量:
基本特点:由内核共享维护的一个"全局变量",用于记录共享资源的数量,限制进程对资源的访问
1、如果变量的值大于0,说明可以使用资源,此时需要将变量值-1,然后才能使用资源
2、如果变量的值等于0,说明没有资源可以使用,此时进程会进入休眠,直到变量大于0,进程被唤醒,执行步骤1
3、当资源使用完毕时,变量的值+1,正在休眠的进程可以被唤醒了

int semget(key_t key, int nsems, int semflg);
功能:创建/获取信号量
key:IPC键值
nsems:信号量的数量 一般写1即可
semflg:
    IPC_CREAT   创建
    IPC_EXCL    存在则返回-1
    mode:       权限
返回值:IPC标识符 失败返回-1

int semop(int semid, struct sembuf *sops, unsigned nsops);
功能:对信号量进行加减操作
semid:IPC标识符
sops:
     struct sembuf
     {
       unsigned short sem_num;  // 信号量的下标
       short          sem_op;   
                    1   信号量+1
                    0   等待信号量的值为0
                   -1   信号量-1,如果不能-1,则阻塞
       short          sem_flg;
                IPC_NOWAIT  不阻塞
                SEM_UNDO    如果进程终止还没有还原信号量,系统将自动还原
     }
nsops:表示sops指针指向多少个结构体,一般写1

int semctl(int semid, int semnum, int cmd, ...);
功能:删除/控制信号量
semid:IPC标识符
semnum:信号量的下标
cmd:
    IPC_STAT    获取信号量属性
    IPC_SET     设置信号量属性
    IPC_RMID    删除信号量
    GETALL      获取所有信号量的值
    GETVAL      获取某个信号量的值
    GETNCNT     获取所有等待减信号的进程数量
    SETALL      设置所有信号量的值
    SETVAL      设置某个信号量的值
union semun {
    int              val;    // 用于设置信号量的值
    struct semid_ds *buf;    // 信号量的属性
    unsigned short  *array;  // 批量获取/设置信号量的值
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值