Linux进程间通信(上)(管道、消息队列)

本文详细介绍了Linux系统中的进程间通信,重点讲解了管道(无名管道和命名管道)和消息队列。无名管道是半双工的,主要用于父子进程或兄弟进程间的通信;命名管道FIFO则允许无关进程之间通信。消息队列是内核中存储的消息链表,支持消息的随机查询和优先级。文中还提供了创建、发送、接收和控制消息队列的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

前言

一、管道

(1)无名管道

(2)命名管道

二、消息队列

       创建消息队列 

        发送消息队列

        读取消息队列

        控制消息队列

        ftok函数

实现消息队列的接收和发送

实现相互发送接收,两者同理


前言

        进程间通信的目的:

        1、数据传输:一个进程需要将它的数据发送给另一个进程
        2、资源共享:多个进程之间共享同样的资源
        3、通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)
      4、 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常

        进程间通信:IPC(InterProcess Communication

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

一、管道

        管道,通常指无名管道,是UNIX系统IPC最古老的形式

        特点

1、半双工(即数据只能在一个方向流动),具有固定的读端和写端

2、只用于父子进程和兄弟进程之间通信

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

4、同一时间,数据只能是单向的,一边读一边写

5、管道的数据,读走就没

  (1)无名管道

NAME
       pipe, pipe2 - create pipe

SYNOPSIS
       #include <unistd.h>

       int pipe(int pipefd[2]);

##int pipefd[2] 定义一个两个元素的数组

            代码实现:

#include<stdio.h>
#include <unistd.h>
#include<string.h>
#include <stdlib.h>

int main ()
{

        int fd[2];


        int pid;
        char readBuf[128]={0};
        if(pipe(fd)==-1){
        printf("creat pipe fail\n");

        }

        pid=fork();

        if(pid<0){
                printf("creat fail\n");
        }else if(pid>0){//进入父进程
                sleep(1);
                printf("this is father\n");
                close(fd[0]);//关闭读端
                write(fd[1],"hello helloo",strlen("hello helloo"));//把数据写入管道
        }else{//进入子进程

                printf("this is child\n");
                close(fd[1]);//关闭写端
                read(fd[0],readBuf,128);//读取缓冲区数据
                printf("%s\n",readBuf);//输出数据


        }


        return 0;

}

执行成功。

(2)命名管道

FIFO,也称为命名管道,它是一种文件类型

        特点:

                1、FIFO可以在无关的进程之间交换数据,与无名管道不同

                2、FIFO有路径名与之关联,它以一种特殊设备文件形式存在于文件系统中

   函数原型:

NAME
       mkfifo - make a FIFO special file (a named pipe)

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

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

##第一个参数是创建管道的名字
##第二个参数是创建管道的权限

创建命名管道,代码如下:

 if((mkfifo("./file",0600)==-1) && errno!=EEXIST){
        //若命名管道文件创建失败且管道文件不存在输出错误信息
        printf("mkfifo error\n");
        perror("why");

        }

使用命名管道实现进程间通信

读端:

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>

int main(){
        int fd;
        char readBuf[30]={0};
        if((mkfifo("./file",0600)==-1) && errno!=EEXIST){

        printf("mkfifo error\n");
        perror("why");

        }
        fd=open("./file",O_RDONLY);
        int nread=read(fd,readBuf,30);
        printf("have %d ,context is %s\n",nread,readBuf);
        close(fd);
        return 0;
}

写端:

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include<string.h>
#include <fcntl.h>

int main(){
        int fd;
        char *str="hello hello";
        fd=open("./file",O_WRONLY);
        write(fd,str,strlen(str));
        close(fd);
        return 0;
}

二、消息队列

        消息队列,是消息的链接表,存放在内核中,一个消息队列由一个标识符(即队列ID)来标识。

        特点:

        1、消息队列是面向记录的,其中的消息具有特定的格式一级特定的优先级

        2、消息队列独立于发送与接受进程。进程终止时,消息队列及其内容并不会被删除

        3、消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取

       创建消息队列 

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);

key_t key: 创建新的消息队列
int msgflg: 赋予新消息队列的权限,IPC_CREAT|0777

成功返回队列ID,失败返回-1

        发送消息队列

 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
成功返回0,失败返回-1

int msqid:            消息队列标识符
const void *msgp:     msgp是一个任何类型的结构体,是消息队列的地址
size_t msgsz:         要发送消息的大小,不含消息类型占用的4个字节,即mtext的长度
int msgflg:           默认写0,当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列 


const void *msgp的结构体如下:
struct msgbuf{

    long mtype;        //message type,must be>0
    char mtext[128];    //message data
}

        读取消息队列

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

      
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
成功返回消息数据的长度,失败返回-1

int msqid         :消息队列标识符
void *msgp        :存放消息队列的结构体,结构体类型要与msgsnd函数发送的类型相同
size_t msgsz      : 要接受消息的大小,不含消息类型占用的4个字节
long msgtyp       :要读消息的类型,如写:888
int msgflg        :默认写0:阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待

        控制消息队列

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

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


int msqid                :消息队列标识符
int cmd                  : IPC_RMID删除节点 用的最多
struct msqid_ds *buf     :NULL

        ftok函数

        系统建立IPC通讯(消息队列、信号量、共享内存)时必须制定一个ID值。通常情况下,该ID值通过ftok函数得到。

key_t key;
key=ftok(".",1);

第二空参数可以为任意数值

实现消息队列的接收和发送

接收信息:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<stdio.h>
      // int msgget(key_t key, int msgflg);
//      int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

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


struct msgGet {
               long mtype;       /* message type, must be > 0 */
               char mtext[128];    /* message data */
           };



int main(){
        struct msgGet readBuf;

        int msgId=msgget(0x1234,IPC_CREAT|0777);

        if(msgId==-1){
        printf("creat queue fail\n");
        }

        msgrcv(msgId, &readBuf, sizeof(readBuf.mtext), 888,0);
        printf("context is %s\n",readBuf.mtext);

       
        return 0;

}

发送信息:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<stdio.h>
      // int msgget(key_t key, int msgflg);
//      int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

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


struct msgSend {
               long mtype;       /* message type, must be > 0 */
               char mtext[128];    /* message data */
           };



int main(){
        struct msgSend sendBuf={888,"this is senddata! haha"};

        int msgId=msgget(0x1234,IPC_CREAT|0777);
        if(msgId==-1){
                printf("creat queue fail\n");
        }


        msgsnd(msgId, &sendBuf, sizeof(sendBuf.mtext),0);
        
        return 0;

}

实现相互发送接收,两者同理

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<stdio.h>
      // int msgget(key_t key, int msgflg);
//      int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

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


struct msgSend {
               long mtype;       /* message type, must be > 0 */
               char mtext[128];    /* message data */
           };



int main(){
        struct msgSend sendBuf={888,"this is senddata! haha"};
        key_t key;
        key=ftok(".",1);

        int msgId=msgget(key,IPC_CREAT|0777);
        if(msgId==-1){
                printf("creat queue fail\n");
        }


        msgsnd(msgId, &sendBuf, sizeof(sendBuf.mtext),0);
        struct msgSend readBuf;
        msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),988,0);
        printf("context is %s\n",readBuf.mtext);

        msgctl(msgId,IPC_RMID,NULL);


        return 0;

}

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<stdio.h>
      // int msgget(key_t key, int msgflg);
//      int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

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


struct msgGet {
               long mtype;       /* message type, must be > 0 */
               char mtext[128];    /* message data */
           };



int main(){
        struct msgGet readBuf;
        key_t key;
        key=ftok(".",1);
        int msgId=msgget(key,IPC_CREAT|0777);

        if(msgId==-1){
        printf("creat queue fail\n");
        }

        msgrcv(msgId, &readBuf, sizeof(readBuf.mtext), 888,0);
        printf("context is %s\n",readBuf.mtext);

        struct msgGet sendBuf={988,"thank you for reach"};
        msgsnd(msgId,&sendBuf,sizeof(sendBuf.mtext),0);


        msgctl(msgId,IPC_RMID,NULL);
        return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值