精华内容
下载资源
问答
  • 利用消息队列基本函数,实现Linux系统下进程A和进程B之间的消息收发。 msgsend输入‘end’,退出程序
  • 主要介绍了Linux消息队列实现进程间通信实例详解的相关资料,需要的朋友可以参考下
  • 消息队列实现进程间通信

    千次阅读 2017-06-06 21:57:02
    进程间通信 —IPC(InterProcess Communication) 进程间通信是不同的进程通过一个或多个文件来传递信息。经常用到的通信方式有两种,一种是通过管道来实现两个进程间的通信,管道机制是创建的不同进程通过调用管道...

    进程间通信

    IPC(InterProcess Communication)

    进程间通信是不同的进程通过一个或多个文件来传递信息。经常用到的通信方式有两种,一种是通过管道来实现两个进程间的通信,管道机制是创建的不同进程通过调用管道函数在内核中开辟一块空间来实现。而还有一种方式就是使用system V标准,来实现不同进程间的通信,下来就浅谈一下system V标准中的第一种通信方式——消息队列。

    一、什么是消息队列

    消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。  每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值。我们可以通过发送消息来避免命名管道的同步和阻塞问题。


    二、消息队列的特点      


    1.消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识.     

    2.消息队列允许一个或多个进程向它写入与读取消息.      

    3.消息队列的生命周期随内核。

    4.消息队列可以实现双向通信。


    三、消息队列的创建,删除,和属性控制


    1、创建消息队列

    调用的函数msgget()。函数原型 int msgget(key_t key, int msgflg);


    第一个参数key:可以认为是一个端口号,也可以由函数ftok生成。它是一个唯一标识的IPC(相当于身份证号一样),这里的key可以有ftok函数调用生成。

    第二个参数msgflg:msgflg有两个标志,IPC_CREAT和IPC_EXCL。当IPC_CREAT单独使用的时候,若消息队列不存在,则创建一支;若存在打开并返回。


    下来用代码来实现

    key_t _key = ftok(PATHNAME,PROJ_ID);//ftok参数有两个,第一个是路径变量,第二个是projectID
        if(_key < 0){
            perror("ftok");
            return -1;;
        }
        int msgid = msgget(_key,flags);
        if(msgid < 0){
            perror("msgget");
            return -2;
        }
        return msgid;
    


    2、删除消息队列


    当一个消息队列被创建出来之后,肯定要删除它,删除的方式可以是用代码来删除,也可以使用命令来删,现在先来实现以下第一种删除方式,命令删除后面在写
    删除所调用的函数是msgctl()。函数原型 int msgctl(int msqid, int cmd, struct msqid_ds *buf);



    这里的msgctl不仅仅是个删除时用的函数,它是控制型函数。先来看参数,第一个参数msgid一看就是所要删除的消息队列ID,第二个参数是IPC_RMID,第三个直接设置为NULL就行!调用成功返回0,失败返回-1.


    下面用代码来实现!

    if(msgctl(msgid, IPC_RMID, NULL) < 0){
            perror("msgctl");
            return -1;
        }
        return 0;
    

    3、消息队列的属性控制

    既然消息队列是用来实现进程间通信的,那它必然就会有读和写功能。这里的读和写不同,system V是系统提供的第三方接口,和管道不一样,它的其中之一特点是可以实现双向通信。

    读写所调用的函数是msgsnd()和msgrcv

    msgsnd将数据放到消息队列中:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 

    msgrcv从队列中取⽤消息:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int 

    msgflg);   



      msqid:消息队列的标识码
            msgp:指向消息缓冲区的指针,此位置是来暂时存储发送和接收的消息,是一个用户可定义的通用结构

    msgsz:消息的大小。
            msgtyp:从消息队列内读取的消息形态。如果值为零,则表示消息队列中的所有消息都会被读取。

    函数如果调用成功则返回0,失败则返回-1;

    代码实现如下:

    int sendMsg(int msgid, int type, const char *msg)
    {
        struct msgbuf _mb;
        _mb.mtype = type;
        strcpy(_mb.mtext,msg);
        if(msgsnd(msgid, &_mb,sizeof(_mb.mtext),0)<0){
            perror("msgsnd");
            return -1;
        }
        return 0;
    }
    int recvMsg(int msgid, int type, char *out)
    {
        struct msgbuf _mb;
        if(msgrcv(msgid, &_mb, sizeof(_mb.mtext),type,0)<0){
            perror("msgrcv");
            return -1;
        }
    
        strcpy(out,_mb.mtext);
        return 0;
    }
    

    接下来就来整体实现一下通过消息队列两个进程间的通信,首先消息队列是调用相关函数来实现不同的功能的,所以可以用接口的封装来让消息队列直接调用。下面是接口封装函数

    #ifndef _COMM_H_
    #define _COMM_H_ 
    
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    #include <string.h>
    
    #define PATHNAME "."
    #define PROJ_ID 0x6666
    #define SERVICE_TYPE 1
    #define CLIENT_TYPE 2
    
    struct msgbuf{
        long mtype;
        char mtext[1024];
    };
    int creatMsgQueue();
    int getMsgQueue();
    int destroyMsgQueue(int msgid);
    int sendMsg(int msgid, int type, const char *msg);
    int recvMsg(int msgid, int type, char *out);
    
    
    
    
    #endif


    #include "comm.h"
    static int commMsgQueue(int flags)
    {
        key_t _key = ftok(PATHNAME,PROJ_ID);//ftok参数有两个,第一个是路径变量,第二个是projectID
        if(_key < 0){
            perror("ftok");
            return -1;;
        }
        int msgid = msgget(_key,flags);
        if(msgid < 0){
            perror("msgget");
            return -2;
        }
        return msgid;
    }
    
    int creatMsgQueue()
    {
        return commMsgQueue(IPC_CREAT | IPC_EXCL|0666);
    }
    
    int getMsgQueue()
    {   
        return commMsgQueue(IPC_CREAT);
    }
    
    int destroyMsgQueue(int msgid)
    {
        if(msgctl(msgid, IPC_RMID, NULL) < 0){
            perror("msgctl");
            return -1;
        }
        return 0;
    }
    int sendMsg(int msgid, int type, const char *msg)
    {
        struct msgbuf _mb;
        _mb.mtype = type;
        strcpy(_mb.mtext,msg);
        if(msgsnd(msgid, &_mb,sizeof(_mb.mtext),0)<0){
            perror("msgsnd");
            return -1;
        }
        return 0;
    }
    int recvMsg(int msgid, int type, char *out)
    {
        struct msgbuf _mb;
        if(msgrcv(msgid, &_mb, sizeof(_mb.mtext),type,0)<0){
            perror("msgrcv");
            return -1;
        }
    
        strcpy(out,_mb.mtext);
        return 0;
    }


    接下来就来实现以下不同的进程来调用它了,这point-to-point的方式来实现

    #include "comm.h"
    int main()
    {
        int msgid = creatMsgQueue();//service创建消息队列,client不用继续创建
        char buf[1024];
        while(1){
            buf[0] = 0;
            recvMsg(msgid, CLIENT_TYPE, buf);
            printf("client say# %s\n", buf);
            printf("Please Enter# ");
            fflush(stdout);
            ssize_t s = read(0, buf, sizeof(buf)-1);
            if(s>0){
                buf[s-1] = 0;
                sendMsg(msgid, SERVICE_TYPE, buf);//往msgid里发,发SERVICE_TYPE类型的数据,发BUF
            }
        }
        destroyMsgQueue(msgid);//销毁消息队列
        return 0;
    }
    int main()
    {
        int msgid = getMsgQueue();//service创建消息队列,client不用继续创建
        char buf[1024];
        while(1){
            buf[0] = 0;
            printf("client Enter#");
            fflush(stdout);
            ssize_t s = read(0, buf, sizeof(buf)-1);
            if(s>0){
                buf[s-1] = 0;
                sendMsg(msgid, CLIENT_TYPE, buf);//往msgid里发,发SERVICE_TYPE类型的数据,发BUF
            }
            recvMsg(msgid, SERVICE_TYPE, buf);
            printf("server say# %s\n", buf);
        }
    
        return 0;
    }
    




    当创建一条消息队列之后,如果想再次使用时,会出错。因为在创建消息队列时用到的是IPC_CREAT和IPC_EXCL

    ,所以再次创建时会出错返回。接下来就用要使用一条指令来删除它


    查看系统中的消息队列的命令:ipcs -q

    删除系统中的消息队列的命令:ipcrm -q 消息队列id号







    展开全文
  • 之前介绍了进程间通信的PIPE通信、FIFO通信和共享内存,三种通信方式各有其适用范围。 今天介绍第四种进程通信方式—消息队列消息队列的概念 消息队列从字面理解就是消息组成的列表。进程能够从消息队列添加消息...

    之前介绍了进程间通信的PIPE通信、FIFO通信和共享内存,三种通信方式各有其适用范围。

    今天介绍第四种进程通信方式—消息队列。

    消息队列的概念

    消息队列从字面理解就是消息组成的列表。进程能够从消息队列添加消息和读取消息。

    乍一看消息队列类似于FIFO通信,但消息队列能够实现消息的随机查询,有些读者会疑惑这是什么意思呢?

    FIFO中的信息必须按照信息的先后顺序进行读取,而消息队列能够指定读取某条消息,即不必按照顺序读取消息。

    另外,进程通过消息队列添加和读取的消息也保存在linux内核中,由“队列ID”进行标识。

    消息队列的实现步骤

    消息队列的实现较为简单,分为以下步骤:

    (1)创建并打开消息队列。通过函数msgget()创建并打开消息队列。

    (2)添加消息。通过函数msgsnd()函数将进程的消息添加到消息队列中。

    (3)读取消息。通过函数msfrcv()函数把消息从消息队列读取到进程中。

    NOTE:在创建消息队列时,需要利用ftok函数将一条已存在的路径和一个整数转换成类型为key_t的键值,这是由于msgget()函数需要利用ftok的返回值生成消息队列的ID。

    消息队列的代码实现

    下面是共享内存的代码实现(在linux环境下编译通过):

    发送进程的代码实现:

    //发送进程
    #include<unistd.h>
    #include<sys/types.h>
    #include<sys/wait.h>
    #include<sys/ipc.h>
    #include<sys/shm.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    
    #define MAX_BUFFER_LEN 1024
    
    //定义消息结构体
    struct message
    {
      long msg_type;
      char msg_text[MAX_BUFFER_LEN];
    };
    
    int main()
    {
      int msg_id;
      key_t key;
      struct message msg;
      
      key = ftok(".", 'a');//利用ftok函数将当前目录与'a'共同转化为key_t类型的键值
      if(key == -1)
      {
        perror("ftok");
        exit(1);
      }
    
      msg_id = msgget(key, IPC_CREAT|0666);//创建消息队列,并设置文件权限掩码0666
      if(msg_id == -1)
      {
        perror("creat msg");
        exit(1);
      }
      else
      {
        printf("the message queue ID is %d\n", msg_id);
      }
      
      while(1)
      {
        printf("enter some message to the queus:");
        if(fgets(msg.msg_text, MAX_BUFFER_LEN, stdin) == NULL)
        {
          puts("no message");
          exit(1);
        }
        msg.msg_type = getpid();
        if(msgsnd(msg_id, &msg, strlen(msg.msg_text), 0) == -1)//添加消息到消息队列
        {
          perror("message posted.\n");
          exit(1);
        }
        if(strncmp(msg.msg_text, "quit", 4) == 0)//如果接收的消息为quit,则退出接收进程
        {
          break;
        }
      }
    
      exit(0);//发送进程正常结束
      return 0;
    }
    

    接收进程的代码实现:

    //接收进程
    #include<stdio.h>
    #include<sys/types.h>
    #include<sys/wait.h>
    #include<sys/ipc.h>
    #include<sys/shm.h>
    #include<stdlib.h>
    #include<string.h>
    #include<unistd.h>
    
    #define MAX_BUFFER_LEN 1024 
    
    //定义消息的结构体
    struct message
    {
      long msg_type;
      char msg_text[MAX_BUFFER_LEN];
    
    };
    
    int main()
    {
      int msg_id;
      int key;
      struct message msg;
      
      key = ftok(".", 'a');//利用ftok函数将当前目录与'a'共同转化为key_t类型的键值
      if(key == -1)
      {
        perror("creat key");
        exit(1);
      }
    
      msg_id = msgget(key, IPC_CREAT|0666);//创建消息队列,并设置文件权限掩码0666
      if(msg_id == -1)
      {
        perror("get the message queue");
        exit(1);
      }
      else
      {
        printf("receive message ID is %d\n", msg_id);
      }
    
      while(1)
      {
        memset(msg.msg_text, 0, MAX_BUFFER_LEN);//将消息队列清空
        if(msgrcv(msg_id, &msg, MAX_BUFFER_LEN, 0, 0) == -1)//接收进程从消息队列读取消息
        {
          perror("receive mess, error");
          exit(1);
        }
        else
        {
          printf("the message is %s\n", msg.msg_text);
        }
    
        if(strncmp(msg.msg_text, "quit", 4) == 0)//如果接收的消息为quit,则退出接收进程
        {
          break;
        }
      }
      
      if(msgctl(msg_id, IPC_RMID, NULL) < 0)//IPC_RMID为从进程中删除消息队列
      {
        perror("msgctl");
        exit(1);
      }
      exit(0);//接收进程正常结束
      return 0;
    }
    

    Note:接收进程和发送进程均利用msgget函数创建消息队列,由于使用的消息队列的键值一致,所以返回的消息队列ID也是一样的,从而实现进程间消息传递。

    下图是运行结果:
    在这里插入图片描述

    Note:在两个终端中分别运行接收进程和发送进程。

    总结

    消息队列是进程间通信的一种常用方式,其广泛应用于实际项目中多进程的通信,感兴趣的读者可以自己在电脑上尝试实现消息队列通信。

    当然,进程间的通信方式还有socket、信号和信号量。关于socke的通信原理还在学习中,后续将在公众号上更新。关于信号和信号量将会在线程的同步与互斥中介绍。

    ps: 欢迎关注我的公众号[酷酷的coder],分享转行菜鸟程序员成长过程汇总的烦恼和反思.
    在这里插入图片描述

    展开全文
  • Linux消息队列实现进程间通信

    千次阅读 2017-06-02 23:58:53
    消息队列提供了从一个进程向另一个进程发送一个有类型数据块的方法。用这种方法可以避免命名管道的同步和阻塞问题。消息队列是基于消息的,而管道是基于字节流的,并且消息队列的读取不一定是先入先出。 消息队列...
     
    
    什么是消息队列:
    消息队列提供了从一个进程向另一个进程发送一个有类型数据块的方法。用这种方法可以避免命名管道的同步和阻塞问题。消息队列是基于消息的,而管道是基于字节流的,并且消息队列的读取不一定是先入先出。

    消息队列的操作:
    消息队列的创建或者获取:
    int msgget(key_t key, int msgflg);
    参数描述:
    key:是一个端口号,可以由ftok()生成
    msgflg:  IPC_CREAT:如果IPC不存在,则创建,存在就打开
                    IPC_EXECL:单独使用无太大意义,与IPC_CREAT一块使用代表,IPC不存在创建,存在出错,返回
    key_t ftok(const char *pathname, int proj_id);
    生成唯一一个key供用户使用,返回一个消息队列标识符。
    返回值:
    成功返回消息队列的id,失败返回-1。
    读取消息:
    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
    参数描述:
    msgid:消息队列的标识符
    msgp:指向一个缓冲区的指针,用来暂时存放储存发送和接受的消息,是一个用户可以定义的通用结构。
    struct msgstru{
        long mtype; //大于0
        char mtext;//用户指定大小
    };
    msgz:消息的大小
    msgtyp:从消息队列中读取的消息形态
    msgflg:用来指明核心程序在队列没有数据的情况下所应采取的行动。如果msgflg和常 数IPC_NOWAIT合用,则在msgsnd()执行时若是消息队列已满,则msgsnd()将不会阻塞,而 会立即返回-1,如果执⾏行的是msgrcv(),则在消息队列呈空时,不做等待马上返回-1,并设定 错误码为ENOMSG。当msgflg为0时,msgsnd()及msgrcv()在队列呈满或呈空的情形时,采取 阻塞等待的处理模式。
    返回值:
    成功返回实际读取到的字节数,失败返回-1。
    发送消息:
    int msgsnd(int msqid, const void *msgp, size_t msgz, int msgflg);
    参数与读取消息函数的参数相同。
    返回值;
    成功返回0,失败返回-1。

    消息队列的查看:
    可以使用 ipcs -q 来查看系统中的消息队列;
    可以使用ipcrm -q +消息队列id  来删除对应id的消息队列

    消息队列的实例:
    实现一个server和一个client程序,他们之间利用消息队列进行通信。
    comm.h
    #ifndef  _COMM_H_
    #define  _COMM_H_
    #ifndef  _COMM_H_
    #define  _COMM_H_
    
    #include<stdio.h>
    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<sys/msg.h>
    #include<string.h>
    
    #define PATHNAME "."
    #define PROJ_ID 0x666
    
    #define SERVER_TYPE 1
    #define CLIENT_TYPE 2
    
    //自定义一个缓冲区用来暂时存储发送或者接收的数据
    struct msgbuf
    {
        long mytype;
        char mtext[1024];
    };
    int createMsgQueue();
    int getMsgQueue();
    int destroyMsgQueue(int msgid);
    int sendMsg(int msgid, int type, char *msg);
    int recvMsg(int msgid, int recvType, char out[]);
    #endif
    

    comm.c
    #include "comm.h"
    
    //创建或者打开消息队列
    static int commMsgQueue(int flag)
    {
        key_t key = ftok(PATHNAME, PROJ_ID);
        if(key < 0)
        {
        perror("ftok");
        return -1;
        }
        //根据flag的不同选择打开还是创建
        int msgid = msgget(key, flag);
        if(msgid < 0)
        {
        perror("msgget");
        return -2;
        }
        return msgid;
    }
    int createMsgQueue()
    {
        return commMsgQueue(IPC_CREAT|IPC_EXCL|0666);
    }
    int getMsgQueue()
    {
        return commMsgQueue(IPC_CREAT);
    }
    int destroyMsgQueue(int msgid)
    {
        //删除消息队列
        if(msgctl(msgid, IPC_RMID, NULL)<0)
        {
        perror("msgctl");
        return -1;
        }
        return 0;
    }
    //发送消息(参数:发送者,发送内容的类型,发送的内容)
    int sendMsg(int msgid, int who, char *msg)
    {
        //buf 自定义的缓冲区,用来暂存数据
        struct msgbuf buf;
        buf.mytype = who;
        strcpy(buf.mtext, msg);
        //进行发送,将缓冲区中的数据进行发送
        if(msgsnd(msgid, (void *)&buf, sizeof(buf.mtext), 0) < 0)
        {
        perror("msgsnd");
        return -1;
        }
        return 0;
    }
    //接收消息(参数:接受者,接受类型,接受之后存放位置)
    int recvMsg(int msgid, int who, char out[])
    {
        struct msgbuf buf;
        buf.mytype = who;
        //接收数据,将接收的数据写入到缓冲区中
        if(msgrcv(msgid, (void *)&buf, sizeof(buf.mtext), recvType, 0)< 0)
        {
        perror("msgrcv");
        return -1;
        }
        //将数据从缓冲区存放到指定位置
        strcpy(out, buf.mtext);
        return 0;
    }
    

    server.c
    #include"comm.h"
    int main()
    {
        //服务器端进行消息队列的创建
        int msgid = createMsgQueue();
    
        //缓冲区
        char buf[1024];
        while(1)
        {
        buf[0] = 0;
        //接受客户端发送的消息
        recvMsg(msgid, CLIENT_TYPE, buf);
        printf("client #  %s\n", buf);
    
        printf("please enter: ");
        fflush(stdout);
        //从标准输入输入内容到缓冲区
        ssize_t s = read(0, buf, sizeof(buf));
        if(s > 0)
        {
            buf[s-1] = 0;
            //将缓冲区内容发送至客户端
            sendMsg(msgid, SERVER_TYPE, buf);
            printf("send done...\n");
        }
        }
        //服务器端创建,服务器端销毁消息队列
        destoryMsgQueue(msgid);
        return 0;
    }
    

    client.c
    #include "comm.h"
    int main()
    {
        //打开消息队列
        int msgid = getMsgQueue();
    
        //缓冲
        char buf[1024];
        while(1)
        {
        buf[0] = 0;
        printf("please enter:");
        fflush(stdout);
        //从标准输入输入到缓冲
        ssize_t s = read(0, buf, sizeof(buf));
        if(s>0)
        {
            buf[s-1] = 0;
            //将缓冲发送到服务器
            sendMsg(msgid, CLIENT_TYPE, buf);
            printf("send done...\n");
        }
        //接受服务器的回应
        recvMsg(msgid, SERVER_TYPE, buf);
        printf("Server : %s\n", buf);
    
        }
       return 0;
    }
    

    运行结果:


    展开全文
  • 管道和消息队列实现进程间通信

    千次阅读 2017-05-08 17:41:19
    管道和消息队列实现进程间通信管道和消息队列实现进程间通信 管道 基础知识 函数介绍 练习内容 实现代码 消息队列 基础知识 函数介绍 练习内容 实现代码管道基础知识 管道就像现实中的水管,水就像数据。 管道是一...

    管道和消息队列实现进程间通信

    管道

    基础知识

    • 管道

      就像现实中的水管,水就像数据。
      管道是一种半双工的通信方式
      数据只能单向流动,而且只能在具有共同祖先的进程间使用

    函数介绍

    • int pipe(int fd[2])
      功能:创建管道
      参数fd关联:
      一个读端:fd[0]
      一个写端:fd[1]
      头文件<unistd.h>
      这里写图片描述

    • int read(int fd, void *buf, int count);

      功能:从参数fd指定的读端读取管道数据到大小为count的缓存buf中,返回实际读取到的字节数。
      参数
      fd:管道读端
      buf:缓存区,保存读到的数据
      count:读取字节数

    • int write(int fd, void *buf, int count);

      功能:向参数fd指定的写端从缓存buf中取出count个字节到管道中,返回值为实际写入的字节数。
      参数
      fd:管道写端
      buf:缓存区,将要写入管道的数据
      count:写入的字节数

      这里写图片描述

    练习内容

    1.父进程创建管道和两个子进程p1和p2
    2.子进程p1打开给定文件(如果没有,则创建文件),并向文件中写数据,写完关闭文件,然后向管道写入一条消息“ok",目的是通知进程p2可以读取文件内容了。
    3.子进程p2通过管道读取消息,如果消息是“ok”,则打开文件,读取文件内容,并将其输出到屏幕上,关闭文件
    

    实现代码

    /*2.利用管道实现进程间的通信
    编写程序,父进程创建管道和两个子进程p1和p2
    子进程p1打开给定文件(如果没有,则创建文件),并向文件中写数据,写完关闭文件,然后向管道写入一条消息“ok",目的是通知进程p2可以读取文件内容了。
    子进程p2通过管道读取消息,如果消息是“ok”,则打开文件,读取文件内容,并将其输出道屏幕上**/
    
    //管道是半双工的通信方式
    //数据只能单向流动,而且只能在具有共同祖先的进程间使用。
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>   //管道需要的头文件
    #include <string.h>
    //#include <mem.h>   //memset()函数
    #include <fcntl.h>
    #define BUFFER_SIZE 1024
    
    int write_file()  //把内容写到文件里面去
    {
        int f=open("a.txt",O_WRONLY|O_CREAT,0660);//打开指定路径的文件,如果不存在自动创建
        //f为一文件指针
        if(f==-1) //打开失败
        {
            printf("open file error !\n");
            return 0;
        }
        char buffer[]="this is a file";//写到文件里面去的内容
        write(f,buffer,sizeof(buffer));
        //向参数f指定的写端从缓存buf中取指定大小的字节到管道中
        //返回值为实际写入的字节数
        close(f);//关闭文件
        return 1;
    }
    int read_file(char *buffer)
    {
        int f=open("a.txt",O_RDONLY,0660);//打开指定路径的文件,如果不存在自动创建
        if(f==-1)//打开文件失败
        {
            printf("open file error !\n");
            return 0;
        }
        int numofchar=read(f,buffer,BUFFER_SIZE); //f代表读端
        //不知道缓冲区有多少有效的数据,所以把buffer大小的内容全读出来 
        //从参数f指定的读端读取管道数据到指定大小为的缓存buf中
        //返回实际读取到的字节数
        close(f);
        return numofchar;
    }
    int main(int argc,char *argv[])
    {
        int fd[2];  //创建管道的读写端(fd【0】读,fd【1】写)
        if(pipe(fd)<0)//创建管道
        {
            perror("pipe");//错误输出函数,没有错误的时候就显示 error 0
            exit(0);
        }
            char mas[100];
            int n;
            memset(mas,0,sizeof(mas)); //清空buf内容为0
            //一个字节一个字节的设定为指定值
        //build son
        pid_t p1;
        p1=fork();
        if(p1<0)  //创建进程失败
        {
            fprintf(stderr,"fork failed");
            exit(-1);
        }
        else if(p1==0)//son
        {
        //子进程p1打开给定文件(如果没有,则创建文件)
        //并向文件中写数据,写完关闭文件,然后向管道写入一条消息“ok"
        //目的是通知进程p2可以读取文件内容了
            if(write_file())  //调用写文件函数
            {
                close(fd[0]);  //close read
                char *massage = "ok";
                write(fd[1],massage,100); //写管道消息
                //ok 写到fd【1】里面
            }
        }
        else  //father
        {
            pid_t p2;
            p2=fork();
            if(p2<0)//创建进程失败
            {
                fprintf(stderr,"fork failed");
                exit(-1);
            }
            else if(p2==0)//son
            {
                close(fd[1]); //close write
                read(fd[0],mas,sizeof(mas));// 从 读端读消息
                if(!strcmp(mas,"ok"))  // is "ok" or no
                {
                    char data[BUFFER_SIZE];
                    int n =read_file(data);  //读取文件里面的内容并存到data中
                    printf("data of file is : %s. \n",data);//打印出来
                }
            }
            else  //father
            {
                exit(0);
            }
        }
    
        return 0;
    }

    消息队列

    消息队列提供了一种由一个进程向另一个进程发送块数据的方法。
    每一个数据块被看作有一个类型,接收进程可以独立接收具有不同类型的数据块。

    基础知识

    • 消息队列

      消息的链接表,简称:队列
      标识符:队列ID
      队列中消息的结构:
      这里写图片描述

    函数介绍

    • int msgget(key_t key, int flag)
      头文件:<sys/msg.h>
      功能:打开一个队列或创建一个新队列
      返回值:一个队列id
      参数:
      key:标示符,也称为键。可理解为唯一的端口获取key的方法:
      函数ftok(const char* path,int id)
      ftok的功能由一个路径名和项目id产生一个键
      如:key = ftok(“.”, ‘t’);
      flag:控制标记,指定以何种方式创建
      如:0660 | IPC_CREAT

    • int msgsnd(int msqid, const void * ptr, size_t nbytes, int flag)

      头文件:<sys/msg.h>
      功能:往消息队列写消息,即发送消息。
      参数:
      msqid:队列id
      ptr:要发送消息的结构指针,指向消息的地址
      nbytes:发送的字节数
      flag:控制标记,一般指定为IPC_NOWAIT

    • int msgrcv(int msqid, const void * ptr, size_t nbytes ,long type, int flag) ;

      头文件:<sys/msg.h>
      功能:从消息队列读消息,即接收消息。
      参数:
      msqid:队列id
      ptr:接收的消息保存到该指针指向的消息结构
      nbytes:接收的字节数
      type
      ==0返回队列第一个消息
      >0返回队列中类型为type的第一个消息
      <0返回小于或等于type绝对值的消息
      flag:控制标记,一般指定为IPC_NOWAIT

    练习内容

    父进程创建消息队列和两个子进程p1和p2
    子进程p1打开给定文件(如果没有,则创建文件),并向文件中写数据,写完关闭文件,然后向消息队列写入一条消息“ok”,目的是通知进程p2可以读取文件内容了。
    子进程p2从消息队列读取消息,如果收到消息“ok”,则打开文件,读取文件内容,并将其输出道屏幕上,关闭文件。
    

    实现代码

    /*父进程创建消息队列和两个子进程p1和p2
    子进程p1打开给定文件(如果没有,则创建文件),并向文件中写数据,写完关闭文件,然后向消息队列写入一条消息“ok”,目的是通知进程p2可以读取文件内容了。
    子进程p2从消息队列读取消息,如果收到消息“ok”,则打开文件,读取文件内容,并将其输出道屏幕上,关闭文件。
    */
    #include<stdio.h>
    #include<sys/msg.h>
    #include<fcntl.h>
    #include<stdlib.h>
    #include<string.h>
    #define NUM 100
    //消息通信
    //消息队列提供了一种由一个进程向另一个进程发送块数据的方法。
    //每一个数据块被看作有一个类型,接收进程可以独立接收具有不同类型的数据块。
    struct mymsg
    {
            long mytype;  //存储消息类型
            char mytext[NUM];//存储消息内容
    };
    
    int main()
    {
            FILE *f;   //文件指针
            pid_t p1,p2;// 两个进程
            key_t key; 
            key = ftok(".", 't');
            //系统IPC键值的格式转换函数
            char s[20];
            int mgsid;
            if((mgsid=msgget(key,IPC_CREAT|0666))==-1)//打开一个队列或创建一个新队列
    
            {
                    printf("creat error\n");
                    return -1;
            }
    
            p1=fork();
            if(p1<0)
            {
            fprintf(stderr,"fork failed");
            exit(-1);
            }
            else if(p1==0)
            {
                printf("p1 pid is:%d\n",getpid());  //p1id
                printf("sending the massage...\n");
                sleep(1);  //本线程休眠1毫秒
                struct mymsg msg1;
                msg1.mytype=getppid(); //父进程id
                if((f=fopen("hello.txt","w"))==NULL) //打开文件失败
                {
                        printf("the file %s not open\n","hello.txt");
                        return ;
                }
                fputs("hello!",f);//送一个字符到一个流中 
                fclose(f);
                strcpy(msg1.mytext,"ok");  
                if(msgsnd(mgsid,&msg1,sizeof(msg1.mytext),0)<0)//往消息队列写消息,即发送消息。
    
                {
                        printf("sending error!\n");
                        exit(-1);
                }
                else
                {
                        printf("complete sending !\n");
                        exit(0);
                }
    
            }
            else
            {
                wait(NULL);
                p2=fork();
                if(p2<0)
                {
                        printf("fork creat error!\n");
                        exit(1);
                }
                else if(p2==0)
                {
                        printf("p2 pid is:%d\n",getpid());
                        printf("Receiving the massage...\n");
                        sleep(1);//本线程休眠1毫秒
                        struct mymsg msg2;
                        msg2.mytype=getppid();
                        if(msgrcv(mgsid,&msg2,NUM,getppid(),0)<0)//从消息队列读消息,即接收消息
                        {
                                printf("receving error!!!\n");
                                exit(1);
                        }
                        else
                        {
                                printf("complete receving \n");
    
                                if(strcmp("ok",msg2.mytext)==0)
                                {
                                        if((f=fopen("hello.txt","r"))==NULL)
                                        {
                                                printf("the file %s no opend.\n","hello.txt");
                                                return;
                                        }
                                        while((fgets(s,20,f))!=NULL)//从流中读一行或指定个字符
                                        {
                                                printf("the massage is:%s\n",s);
                                        }
                                        fclose(f);
                                }
                        }
    
                    }
                    else
                    {
                        wait(NULL);
                        exit(0);
                    }
            }
            return 0;
    }

    本博客内容到此介绍,欢迎指正!

    展开全文
  • UNIX环境下如何应用消息队列实现进程间通信[汇编].pdf
  • linux消息队列实现进程间通信

    千次阅读 2017-06-07 22:22:30
    进程间通信(IPC):进程间通信的本质就是通过让不同的进程看到一份公共的资源来实现通信。 常用的进程间通信的方式有两种:通过管道和systemv标准,今天我们来介绍systemv标准中的一种:消息队列 消息队列消息...
  • Linux下利用消息队列实现进程间通信

    千次阅读 2014-07-12 11:17:23
    消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题。但是...
  • 消息队列就是由内核负责管理的一个管道,可以按顺序发送消息包(消息类型+消息内容),可以全双工工作,可以不按消息的顺序接收消息。 int msgget(key_t key, int msgflg); 功能:创建/获取消息队列 key:IPC键值...
  • 通过对进程间通信消息队列)的设计,深入理解进程之间是如何通过消息 队列进行通信的。 实验原理 消息队列就是一个消息的链表。可以把消息看作一个记录,具有特定的格式以及特定的优先级。 对消息队列有写权限的...
  • 操作系统课程实验报告 实习题目 进程间基于消息队列通信 指导教 学生姓名 学 号 日 期 实现工具 C 语言 实现环境 Linux 系统 实验目的 系统了解linux 系统的通信机构IPC 掌握IPC 中消息通信机 制理解消息通信的...
  • 分别编写代表两个人的程序,他们之间用消息队列进行通信,注意箭头是双向的!注意: 1. Jack与Rose必须可以同时收与发 2. Jack发送了“quit”给对方,自己与Rose都要退出 ...
  • 消息队列实现的可以两个人正常交流。 在此之前,我们先来了解一下消息队列: *unix早期通信机制之一的信号能够传送的信息量有限,管道则只能传送无格式的字节流,这无疑会给应用程序开发带来不便。消息队列(也...
  • Linux C消息队列实现进程间通信

    千次阅读 2017-11-27 15:45:06
    Linux C消息队列实现进程间通信 什么是消息队列 消息队列是内核地址空间中的内部链表,通过Linux内核在各个进程之间传递内容,内核中的消息队列是通过IPC的标识符来区别的,不同的消息队列之间是相对独立的。每个...
  • 使用消息队列进行进程间通信(代码实例)
  • 关于Linux系统进程通信的概念及实现可查看:...我们需要利用sysvmsg模块提供的函数来进进程间通信。先来看一段示例代码_1: 复制代码 代码如下: <?php $message_queue_key = ftok(__
  • 进程间通信消息队列

    千次阅读 2018-03-21 23:42:19
    我们知道用管道来实现进程间通信的机制是两个进程利用管道文件来实现数据交流,那么消息队列与管道有什么区别呢? 首先看一下管道通信机制的模型: 然后消息队列通信模型: 从上面图中可看出两者有着本质的...
  • 使用linux消息队列实现进程间双向通信。本接口将消息接收封装在一个独立线程中,方便使用。
  • 实现利用消息队列进程间通信之前,先了解一下基本的概念和所需要用到的函数。 消息队列 消息队列是Linux内核地址空间中的内部链表,各个进程可以通过它来进行消息传递。 进程发送的消息会顺序写入消息队列之中...
  • 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题。但是...
  • 本文实例讲述了Python进程间通信Queue消息队列用法。分享给大家供大家参考,具体如下: 进程间通信-Queue Process之间有时需要通信,操作系统提供了很多机制来实现进程间的通信。 1. Queue的使用 可以使用...
  • 最近在Hi3515上调试Qt与DVR程序,发现他们之间使用消息队列通信的,闲暇之余,就总结了一下消息队列,呵呵,自认为通俗易懂,同时,在应用中也发现了消息队列的强大之处。  关于线程的管理(互斥量和条件变量)见:...
  • C#实现进程间通信(使用消息队列实现) 做得比较简单,但是基本实现了功能
  • C#进程间通信-消息队列代码实例。用实现了2个进程,他们之间使用消息队列方式进行通信。
  • ----下面给出一个运用消息队列,实现进程通信的实例。以下程序在IBMRS/6000小型机(AIX操作系统)上和IBMPC(UNIX操作系统)上分别调试通过。该程序主要模拟根据帐号查询余额的过程。包括三方面: 请求进程从标准...
  • 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取.比FIFO更有优势。  目前主要有两种类型的消息队列:POSIX消息队列以及系统V消息队列,系统V消息队列目前被大量使用。...
  • Linux系统下-进程间通信消息队列-详解)

    万次阅读 多人点赞 2016-04-12 12:31:52
    Linux下,进程间通信方式: #(1)管道(Pipe)及有名管道(named pipe): #(2)信号量: #(3)共享内存: #(4)消息队列: #(5)套接口(Socket) #(6)信号(Signal):

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 106,697
精华内容 42,678
关键字:

消息队列实现进程间通信