Linux进程间通信——使用System V 消息队列

消息队列

消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题。但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制。
Linux用宏MSGMAXMSGMNB来限制一条消息的最大长度和一个队列的最大长度。

在Linux中使用消息队列

Linux提供了一系列消息队列的函数接口来让我们方便地使用它来实现进程间的通信。

msgget 函数

创建和访问一个消息队列 :

原型

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

int msgget(key_t key, int msgflag);

参数

key:某个消息队列的名字,用ftok()产生
msgflag:有两个选项IPC_CREAT和IPC_EXCL,单独使用IPC_CREAT,如果消息队列不存在则创建之,如果存在则打开返回;单独使用IPC_EXCL是没有意义的;两个同时使用,如果消息队列不存在则创建之,如果存在则出错返回。

返回值

成功返回一个非负整数,即消息队列的标识码,失败返回-1。

ftok 函数

原型

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

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

调用成功返回一个key值,用于创建消息队列,如果失败,返回-1。

msgctl 函数

消息队列的控制函数

原型

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

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

参数

msqid:由msgget函数返回的消息队列标识码
cmd:有三个可选的值,在此我们使用IPC_RMID

IPC_STAT 把msqid_ds结构中的数据设置为消息队列的当前关联值
IPC_SET 在进程有足够权限的前提下,把消息队列的当前关联值设置为msqid_ds数据结构中给出的值
IPC_RMID 删除消息队列

返回值

成功返回0,失败返回-1。

msgsnd 函数

把一条消息添加到消息队列中

原型

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

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

参数

msgid:由msgget函数返回的消息队列标识码
msgp:指针指向准备发送的消息
msgze:msgp指向的消息的长度(不包括消息类型的long int长整型)
msgflg:默认为0

返回值

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

消息结构一方面必须小于系统规定的上限,另一方面必须以一个long int长整型开始,接受者以此来确定消息的类型

struct msgbuf
{
     long mtye;
     char mtext[1];
};

msgrcv 函数

是从一个消息队列接受消息

原型

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

参数

与msgsnd相同

返回值

成功返回实际放到接收缓冲区里去的字符个数,失败返回-1

常用命令

显示IPC资源

ipcs -q

手动删除IPC资源

ipcrm

消息最大长度上限(MSGMAX)

cat /proc/sys/kernel/msgmax

系统上消息队列的总数上限(MSGMNI)

cat /proc/sys/kernel/msgmni

每个消息队列的总的字节数(MSGMNB)

cat /proc/sys/kernel/msgmnb

代码示例

定义一个 msgque.h 文件

#ifndef __MSGQUE__H__
#define __MSGQUE__H__

#ifdef __cplusplus 

extern "C"
{

#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <getopt.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <pthread.h>
#include <poll.h>
#include <sys/msg.h>

#define MAXLEN 1024
#define MSG_KEY_DIR "/tmp"

typedef struct
{
    long Type;
    char Content[MAXLEN];
}MsgInfo;

key_t GenKey();
int CreateMessage(key_t qid);
int GetMessage(key_t qid);
int SendMessage(int msgid,const char* msg,int type);
int ReceiveMessage(int msgid,char* msg,int type);
int DestoryMessage(int msgid);
int MessageCommon(key_t key,int flag);

#ifndef MSG

#define MSG(fmt...)       do {        printf("{%s}-[%s]-%d: ", __FILE__,__FUNCTION__, __LINE__);        printf(fmt);    }while(0)

#endif

#ifdef __cplusplus 

}

#endif

#endif

定义 msgque.c 文件

# include "msgque.h"

key_t GenKey(const char*pathname,int proj_id)
{
    return ftok(pathname,proj_id);
}

int CreateMessage(key_t qid)
{
   return MessageCommon(qid,IPC_CREAT|0666);
}

int GetMessage(key_t qid)
{
    return MessageCommon(qid,IPC_CREAT);
}

int SendMessage(int msgid,const char* msg,int type)
{

    MsgInfo buf;
    buf.Type = type;             //消息类型
    strcpy(buf.Content,msg);       //消息内容
    if(msgsnd(msgid,&buf,sizeof(buf.Content),0) == -1)
    {
        MSG("Msg Send Error\n");
        DestoryMessage(msgid);
        return -1;
    }
    return 0;
}

int ReceiveMessage(int msgid,char* msg,int type)
{

    MsgInfo buf;
    if(msgrcv(msgid,&buf,sizeof(buf.Content),type,0)==-1)
    {
        MSG("Msg Recv Error\n");
        DestoryMessage(msgid);
        return -1;
    }

    strcpy(msg,buf.Content);   

    return 0;
}

int DestoryMessage(int msgid)
{

    if(msgctl(msgid,IPC_RMID,NULL) == -1)
    {
        MSG("Msg Destroy Error\n");
        return -1;
    }

    return 0;
}

int MessageCommon(key_t key,int flag)
{

    int ret = 0;
    if((ret=msgget(key,flag))==-1)
    {
        perror("MessageCommon Error:  ");
    }

    return ret;

}

定义send.c 文件

# include "./msgque/msgque.h"

int main()
{
    int running = 1;
    char buffer[MAXLEN];
    MsgInfo data;

    key_t qid = GenKey(MSG_KEY_DIR,0x01);
    int masgid = CreateMessage(qid);   

    while(running)
    {
        printf("Enter data : ");
        fgets(buffer, MAXLEN, stdin);

        SendMessage(masgid,buffer,1);

        if(strncmp(buffer, "end", 3) == 0)
        {
            DestoryMessage(masgid);
            running = 0;
        }        

        usleep(100000);
    }

    return 0;
}

定义recv.c 文件

# include "./msgque/msgque.h"

int main()
{
    int running = 1;
    char buffer[MAXLEN];    

    key_t qid = GenKey(MSG_KEY_DIR,0x01);
    int masgid = GetMessage(qid);   

    while(running)
    {
        ReceiveMessage(masgid,buffer,1);
        printf("You wrote: %s\n",buffer);

        if(strncmp(buffer, "end", 3) == 0)
        {
             running = 0;
        }      

        usleep(100000);
    }

    exit(EXIT_SUCCESS);
}

测试结果:

原文地址:https://www.cnblogs.com/chay/p/10798266.html

时间: 2024-08-14 03:51:17

Linux进程间通信——使用System V 消息队列的相关文章

细说linux IPC(十):system V 消息队列

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] system V消息队列和posix消息队列类似,linux系统这两种消息队列都支持.先来看一下system V消息队列相关操作及其函数. msgget()函数创建一个消息队列或打开一个消息队列. #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h&

进程间通信 System V 消息队列

1.msgget (key_t ket,int flag) ; //创建一个新的消息队列或者访问一个已存在的消息队列 2.msgsnd(int msid, const void *ptr ,size_t length ,int flag ) // 发送 3.msgrcv() //读 4.msgctl(int msid , int cmd ,struct  msqid_ds *buff )//  cmd 提供删除,设置,返回当前 tips : 1.客户端服务端例子 服务端创建两个消息队列,A,B,

嵌入式 Linux进程间通信(七)——消息队列

嵌入式 Linux进程间通信(七)--消息队列 一.消息队列 消息队列用于同一台机器上的进程间通信,是一个在系统内核中用来保存消息的队列,在系统内核中是以消息链表的形式出现.消息链表中节点的结构用msg声明.消息队列是一种从一个进程向另一个进程发送数据块的方法. 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构.消息队列可以避免命名管道的同步和阻塞问题,但是每个数据块都有一个最大长度的限制. 1.msgget函数 #include <sys/types.h> #in

System V消息队列(2)

msgsnd函数 功能:把一条消息添加到消息队列中 原型 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 参数 msgid: 由msgget函数返回的消息队列标识码 msgp:是一个指针,指针指向准备发送的消息, msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型 msgflg:控制着当前消息队列满或到达系统上限时将要发生的事情 返回值:成功返回0:失败返回-1 msgs

利用System V消息队列实现回射客户/服务器

一.介绍 在学习UNIX网络编程 卷1时,我们当时可以利用Socket套接字来实现回射客户/服务器程序,但是Socket编程是存在一些不足的,例如: 1. 服务器必须启动之时,客户端才能连上服务端,并与服务端进行通信: 2. 利用套接口描述符进行通信,必须知道对端的IP与端口. 二.相关函数介绍 下面,我们利用System V消息队列来实现进程间的通信: 首先,我们先来了解一下下面几个函数: 1. msgget: 该函数用于打开或创建消息队列,其作用相当与文件操作函数open. #include

Linux IPC实践(6) --System V消息队列(3)

消息队列综合案例 消息队列实现回射客户/服务器 server进程接收时, 指定msgtyp为0, 从队首不断接收消息 server进程发送时, 将mtype指定为接收到的client进程的pid client进程发送的时候, mtype指定为自己进程的pid client进程接收时, 需要将msgtyp指定为自己进程的pid, 只接收消息类型为自己pid的消息; // client/server进程接收/发送的数据结构 const int MSGMAX = 8192; struct msgBuf

Linux IPC实践(5) --System V消息队列(2)

消息发送/接收API msgsnd函数 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 参数 msgid: 由msgget函数返回的消息队列标识码, 也可以是通过ipcs命令查询出来的一个已经存在的消息队列的ID号 msgp:是一个指针,指针指向准备发送的消息, msgsz:是msgp指向的消息长度, 注意:这个长度不含保存消息类型的那个long int长整型 msgflg:控制着当前消息队列满或到达系统上限时

Linux IPC实践(4) --System V消息队列(1)

消息队列概述 消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法(仅局限于本机); 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值. 消息队列也有管道一样的不足: (1)每个消息的最长字节数的上限(MSGMAX); (2)系统中消息队列的总条数也有一个上限(MSGMNI); (3)每个消息队列所能够保存的总字节数是有上限的(MSGMNB) . 查看系统限制 cat /proc/sys/kernel/msgmax  #最大消息长度限制 cat /proc/sys

LINUX学习:System V消息队列

介绍: 1.消息队列提供了一个从一个进程向另外一个进程发送数据块的方法 2.每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值 3.消息队列也有管道一样的不足,就是每个消息最大的长度是有上限的(MSGMAX),每个消息队列 的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也是有一个上限的.   每个IPC对象都在内核维护着一个数据结构, 消息不同于刘模式,消息是有边界的,消息都是被打包在一个一个的数据包里的. 那么我们看下消息队列结构:       消息队列有4