彩世界开奖app官网-彩世界平台官方网址(彩票平台)
做最好的网站
来自 彩世界开奖app官网 2019-12-06 22:03 的文章
当前位置: 彩世界开奖app官网 > 彩世界开奖app官网 > 正文

linux 进程间通信机制(IPC机制)一消息队列【彩

前言:前面讨论了信号、管道的进程间通信方式,接下来将讨论消息队列。

2.msgget
(1)原型:

        IPC_SET :设置消息队列属性。

  1、简介

  消息队列是消息的链接表 ,存放在内核中并由消息队列标识符标识。我们将称消息队列为
“队列”,其标识符为“队列 I D”。 m s g g e t用于创建一个新队列或打开一个现存的队列。 m s g s n d
用于将新消息添加到队列尾端。每个消息包含一个正长整型类型字段,一个非负长度以及实际
数据字节(对应于长度),所有这些都在将消息添加到队列时,传送给 m s g s n d。 m s g r c v用于从
队列中取消息。我们并不一定要以先进先出次序取消息,也可以按消息的类型字段取消息。

#include <unistd.h>//ftok头函数  
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>//msg头函数

#define PATH "./msg"//指定文件路径
#define TEXT_SIZE 1024

struct msg_st
{
    long int msg_type;
    char text[TEXT_SIZE];
};

int main()
{
    int running = 1;
    int msgid = -1;
    struct msg_st data;
    long int msgtype = 2;//msgtype>0时,要和发送端的一致

    key_t key = ftok(PATH,4);

    msgid = msgget(key, 0666 | IPC_CREAT);
    if(msgid == -1)
    {
        fprintf(stderr, "msgget failed with error: %dn", errno);
        exit(EXIT_FAILURE);
    }

    while(running)
    {
        if(msgrcv(msgid, (void*)&data, TEXT_SIZE sizeof(long int), msgtype, 0) == -1)
        {
            fprintf(stderr, "msgrcv failed with errno: %dn", errno);
            exit(-1);
        }
        printf("You wrote: %sn",data.text);

        if(strncmp(data.text, "end", 3) == 0)
            running = 0;
    }

    //删除消息队列  
    if(msgctl(msgid, IPC_RMID, 0) == -1)
    {
        fprintf(stderr, "msgctl(IPC_RMID) failedn");
        exit(-1);
    }
    exit(0);
}

ENOENT(队列不存在)

  一、系统V IPC

  三种系统V IPC:消息队列、信号量以及共享内存(共享存储器)之间有很多相似之处。

  每个内核中的 I P C结构(消息队列、信号量或共享存储段)都用一个非负整数的标识符
( i d e n t i f i e r )加以引用。

  无论何时创建I P C结构(调用m s g g e t、 s e m g e t或s h m g e t) ,都应指定一个关键字(k e y),关
键字的数据类型由系统规定为 k e y _ t,通常在头文件< s y s / t y p e s . h >中被规定为长整型。关键字由
内核变换成标识符。

  以上简单介绍了IPC,对接下来介绍的消息队列、信号量和共享内存有助于理解。

4.msgrcv
(1)原型:

    msgtyp > 0:收取第一条 msgtyp 类型的消息。

  2、函数介绍

  • ftok函数

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

key_t ftok(const char *pathname, int proj_id);//“/home/linux” , 'a'
功能:生成一个key(键值)

  • msgget函数

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

int msgget(key_t key, int msgflg);

功能:创建或取得一个消息队列对象
返回:消息队列对象的id 同一个key得到同一个对象
格式:msgget(key,flag|mode);
flag:可以是0或者IPC_CREAT(不存在就创建)
mode:同文件权限一样

  • msgsnd函数

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:将msgp消息写入标识为msgid的消息队列
msgp:
struct msgbuf {
long mtype; /* message type, must be > 0 */消息的类型必须>0
char mtext[1]; /* message data */长度随意
};

msgsz:要发送的消息的大小 不包括消息的类型占用的4个字节
msgflg: 如果是0 当消息队列为满 msgsnd会阻塞
如果是IPC_NOWAIT 当消息队列为满时 不阻塞 立即返回

返回值:成功返回id 失败返回-1

  • msgrcv函数

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

功能:从标识符为msgid的消息队列里接收一个指定类型的消息 并 存储于msgp中 读取后 把消息从消息队列中删除
msgtyp:为 0 表示无论什么类型 都可以接收
msgp:存放消息的结构体
msgsz:要接收的消息的大小 不包含消息类型占用的4字节
msgflg:如果是0 标识如果没有指定类型的消息 就一直等待
如果是IPC_NOWAIT 则表示不等待

  • msgctl函数

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msgctl(msgid,IPC_RMID,NULL);//删除消息队列对象

  程序2-2将简单演示消息队列:

  ---  snd.c  ---

#include "my.h"

typedef struct{
    long type;
    char name[20];
    int age;
}Msg;

int main()
{
    key_t key = ftok("/home/liudw",'6');
    printf("key:%xn",key);

    int msgid = msgget(key,IPC_CREAT|O_WRONLY|0777);
    if(msgid<0)
    {   
        perror("msgget error!");
        exit(-1);
    }   

    Msg m;
    puts("please input your type name age:");
    scanf("%ld%s%d",&m.type,m.name,&m.age);
    msgsnd(msgid,&m,sizeof(m)-sizeof(m.type),0);

    return 0;
}

  ---  rcv.c  ---

#include "my.h"

typedef struct{
    long type;
    char name[20];
    int age;
}Msg;

int main()
{
    key_t key = ftok("/home/liudw",'6');
    printf("key:%xn",key);

    int msgid = msgget(key,O_RDONLY);
    if(msgid<0)
    {   
        perror("msgget error!");
        exit(-1);
    }   

    Msg rcv;
    long type;
    puts("please input type you want!");
    scanf("%ld",&type);

    msgrcv(msgid,&rcv,sizeof(rcv)-sizeof(type),type,0);
    printf("rcv--name:%s age:%dn",rcv.name,rcv.age);

    msgctl(msgid,IPC_RMID,NULL);
    return 0;
}

  运行演示:

彩世界开奖app官网 1

彩世界开奖app官网 2

一.头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <sys/ipc.h>

  三、详解ftok函数 

  • ftok根据路径名,提取文件信息,再根据这些文件信息及project ID合成key,该路径可以随便设置。
  • 该路径是必须存在的,ftok只是根据文件inode在系统内的唯一性来取一个数值,和文件的权限无关。
  • proj_id是可以根据自己的约定,随意设置。这个数字,有的称之为project ID; 在UNIX系统上,它的取值是1到255;

 

  为了验证以上观点,对程序2-2稍作修改,将路径和proj_id修改:

  程序3-1如下:

  ---  snd.c  ---

#include "my.h"

typedef struct{
    long type;
    char name[20];
    int age;
}Msg;

int main()
{
    key_t key = ftok("/home",'a');
    printf("key:%xn",key);

    int msgid = msgget(key,IPC_CREAT|O_WRONLY|0777);
    if(msgid<0)
    {   
        perror("msgget error!");
        exit(-1);
    }   

    Msg m;
    puts("please input your type name age:");
    scanf("%ld%s%d",&m.type,m.name,&m.age);
    msgsnd(msgid,&m,sizeof(m)-sizeof(m.type),0);

    return 0;
}

  ---  rcv.c  ---

#include "my.h"

typedef struct{
    long type;
    char name[20];
    int age;
}Msg;

int main()
{
    key_t key = ftok("/home",'a');
    printf("key:%xn",key);

    int msgid = msgget(key,O_RDONLY);
    if(msgid<0)
    {   
        perror("msgget error!");
        exit(-1);
    }   

    Msg rcv;
    long type;
    puts("please input type you want!");
    scanf("%ld",&type);

    msgrcv(msgid,&rcv,sizeof(rcv)-sizeof(type),type,0);
    printf("rcv--name:%s age:%dn",rcv.name,rcv.age);

    msgctl(msgid,IPC_RMID,NULL);
    return 0;
}

  运行演示如下图:

彩世界开奖app官网 3 彩世界开奖app官网 4

  总结:主要介绍了进程间通信的消息队列,有疑问可以留言,一定即时解答。

 

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/msg.h>
#include <errno.h>

#define PATH "./msg"  
#define TEXT_LEN 1024
struct msg_st
{
    long int msg_type;
    char text[TEXT_LEN];
};

int main()
{
    int running = 1;
    struct msg_st data;
    char buffer[TEXT_LEN];
    int msgid = -1;

    key_t key = ftok(PATH,4);

    msgid = msgget(key, 0666 | IPC_CREAT);
    if(msgid == -1)
    {
        fprintf(stderr, "msgget failed with error: %dn", errno);
        exit(EXIT_FAILURE);
    }

    while(running)
    {
        printf("Enter some text: ");
        fgets(buffer, TEXT_LEN, stdin);
        data.msg_type = 2;//如果service端 msgtype>0, client端的msgtype要和service端一致
        strcpy(data.text, buffer);

        if(msgsnd(msgid, (void*)&data, TEXT_LEN sizeof(long int), 0) == -1)
        {
            fprintf(stderr, "msgsnd failedn");
            exit(-1);
        }

        if(strncmp(buffer, "end", 3) == 0)
            running = 0;
        sleep(1);
    }
    exit(0);
}

  二、消息队列

  ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
(2)参数:
  msqid:消息队列标识符
  msgp:存放消息的结构体,结构体类型要与msgsnd函数发送的类型相同
  msgsz:要发送消息的大小,不含消息类型占用的4个字节,即mtext的长度
  msgtyp:
    0:接收第一个消息
    >0:接收类型等于msgtyp的第一个消息
    <0:接收类型等于或者小于msgtyp绝对值的第一个消息
  msgflg:
    0: 阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待
    IPC_NOWAIT:如果没有返回条件的消息调用立即返回,此时错误码为ENOMSG
    IPC_EXCEPT:与msgtype配合使用返回队列中第一个类型不为msgtype的消息
    IPC_NOERROR:如果队列中满足条件的消息内容大于所请求的size字节,则把该消息截断,截断部分将被丢弃
(3)返回值:

    msgid=ftok( path, IPCKEY );[/code]

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

linux消息队列函数

  int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
(2)参数:
  msqid:消息队列标识符
  msgp:发送给队列的消息。msgp可以是任何类型的结构体,但第一个字段必须为long类型
    参照格式如下:
    struct s_msg{ /*msgp定义的参照格式*/
        long type; /* 必须大于0,消息类型 */
        char mtext[256]; /*消息正文,可以是其他任何类型*/
      } msgp;
    msgsz:要发送消息的大小,不含消息类型占用的4个字节,即mtext的长度
    msgflg:
      0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列
      IPC_NOWAIT:当消息队列已满的时候,msgsnd函数不等待立即返回
      IPC_NOERROR:若发送的消息大于size字节,则把该消息截断,截断部分将被丢弃,且不通知发送进程。
(3)返回值:

参数:  

  得到消息队列标识符或创建一个消息队列对象
(5)错误码:
  EACCES:指定的消息队列已存在,但调用进程没有权限访问它
  EEXIST:key指定的消息队列已存在,而msgflg中同时指定IPC_CREAT和IPC_EXCL标志
  ENOENT:key指定的消息队列不存在同时msgflg中没有指定IPC_CREAT标志
  ENOMEM:需要建立消息队列,但内存不足
  ENOSPC:需要建立消息队列,但已达到系统的限制


三.书上看到的例子:

 

3.msgsnd
(1)原型:

fname就时你指定的文件名,id是子序号。

  获取和设置消息队列的属性
(5)错误码:
  EACCESS:参数cmd为IPC_STAT,确无权限读取该消息队列
  EFAULT:参数buf指向无效的内存地址
  EIDRM:标识符为msqid的消息队列已被删除
  EINVAL:无效的参数cmd或msqid
  EPERM:参数cmd为IPC_SET或IPC_RMID,却无足够的权限执行

参数:

  成功 --- 0,失败 --- -1,错误原因存于error中
(4)作用:

    msgsz:消息的大小。

    IPC_STAT:获得msgid的消息队列头数据到buf中
    IPC_SET:设置消息队列的属性,要设置的属性需先存储在buf中,可设置的属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes
    IPC_RMID:删除消息队列,将队列从系统内核中删除
    buf:消息队列管理结构体
(3)返回值:

如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16 进制为0x26,则最后的key_t返回值为0x26010002。

  int msgctl(int msqid, int cmd, struct msqid_ds *buf)
(2)参数:
  msqid:消息队列标识符
  cmd:

    cmd:执行的控制命令,即要执行的操作。包括以下选项:

二.函数
1.ftok
(1)原型:

当删除重建文件后,索引节点号由操作系统根据当时文件系统的使用情况分配,因此与原来不同,所以得到的索引节点号也不同。

  

4、ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); //从消息队列读取信息

  从标识符为msqid的消息队列读取消息并存于msgp中,读取后把此消息从消息队列中删除
(5)错误码:
  E2BIG:消息数据长度大于msgsz而msgflag没有设置IPC_NOERROR
  EIDRM:标识符为msqid的消息队列已被删除
  EACCESS:无权限读取该消息队列
  EFAULT:参数msgp指向无效的内存地址
  ENOMSG:参数msgflg设为IPC_NOWAIT,而消息队列中无消息可读
  EINTR:等待读取队列内的消息情况下被信号中断

#include <sys/types.h>

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

 

      0666|IPC_CREAT --- 如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队列,返回此消息队列的标识符
      0666|IPC_CREAT|IPC_EXCL --- 如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队列则报错
(3)返回值:

    

2.msgsnd

ftok原型如下:

3.msgctl
(1)原型:

    其他参数参考msgsnd函数。

  key_t ftok( char * fname, int id )
(2)参数:
  fname:指定的文件名
id:子序号(虽然为int,但是只有8个比特被使用(0-255))
(3)返回值:

        IPC_CREAT:如果 key不存在,创建

  int msgget(key_t key, int msgflg)
(2)参数:
  key:来源于ftok返回的IPC键值(0(IPC_PRIVATE):会建立新的消息队列)
  msgflg:

        IPC_EXCL:如果 key 存在,返回失败

1.msgrcv.c

    msgp:指向消息缓冲区的指针,此位置用来暂时存储发送和接收的消息,是一个用户可定义的通用结构,形态如下

 

 

  成功 --- key_t值,失败 --- -1
(4)作用:

 

  成功 --- 0,失败 --- -1,错误原因存于error中
(4)作用:

返回说明:  

  成功 --- 0,失败 --- -1,错误原因存于error中
(4)作用:

如果成功,返回消息队列标识符

  将msgp消息写入到标识符为msqid的消息队列
(5)错误码:
  EAGAIN:参数msgflg设为IPC_NOWAIT,而消息队列已满
  EIDRM:标识符为msqid的消息队列已被删除
  EACCESS:无权限写入消息队列
  EFAULT:参数msgp指向无效的内存地址
  EINTR:队列已满而处于等待情况下被信号中断
  EINVAL:无效的参数msqid、msgsz或参数消息类型type小于0

key_t ftok( char * fname, int id )

  成功 ---返回消息队列的标识符,失败 --- -1,错误原因存于error中
(4)作用:

举例:msgctl(qid, IPC_RMID, NULL)  //删除消息队列

EEXIST(队列已经存在,无法创建)

#include <sys/msg.h>


    buf:临时的 msqid_ds 结构体类型的变量。用于存储读取的消息队列属性或需要修改的消息队列属性。

同一段程序,用于保证两个不同用户下的两组相同程序获得互不干扰的IPC键值。

        IPC_NOWAIT:如果需要等待,直接返回错误

    msqid:消息队列的标识符。

 


参数:

    sprintf( path, "%s/etc/config.ini", (char*)getenv("HOME") );

----------------------------------------------------- linux消息队列函数 -------------------------------- 头文件: #include sys/types.h #include sy...

        这 4 条命令(IPC_STAT、IPC_SET、IPC_INFO 和 IPC_RMID)也可用于信号量和共享存储。

#define IPCKEY 0x111

2、int msgget(key_t key, int msgflg); //创建消息队列

5、int msgctl (int msqid, int cmd, struct msqid_ds *buf); //消息队列属性控制 

char path[256];

摘自 pj81102的专栏

由于 etc/config.ini(假定)为应用系统的关键配置文件,因此不存在被轻易删除的问题——即使被删,也会很快被发现并重建(此时应用系统也将被重起)。

msgid=msgget(IPC_PRIVATE,IPC_CREAT|IPC_EXCL|00666); //创建消息队列

头文件:

举例:msgsnd(g_msg_id,&msg_snd,sizeof(msg_snd.msg_item),IPC_NOWAIT); //非阻塞发送消息    

  www.2cto.com  

如果要确保key_t值不变,要目确保ftok的文件不被删除,要么不用ftok,指定一个固定的key_t 值,比如:


    key:消息队列关联的键。为IPC_PRIVATE时表示创建自己的消息队列

    msgflg:用来指明进程在队列数据满(msgsnd)或空(msgrcv)的情况下所应采取的行动。

 

struct msgbuf {

举例:

    msgtyp:

};

        如果单独使用IPC_CREAT,则msgget()要么返回一个新创建的消息队列的标识符,要么返回具有相同关键字值的队列的标识符。如果 IPC_EXCL和IPC_CREAT一起使用,则msgget()要么创建一个新的消息队列,要么如果队列已经存在则返回一个失败值-1。

    

成功执行时,msgsnd()返回0, 失败返回-1

    

linux消息队列函数

ftok()的设计目的也在于此。

返回说明:  

 

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

  www.2cto.com  

在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。

3、int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); //将消息送入消息队列

    msgtyp = 0:收取队列中的第一条消息,任意类型。

举例:msgrcv(msgid,&msg_rbuf,sizeof(msg_rbuf.msg_item),10,0); //阻塞接收

ENOSPC(超出最大队列限制) 

 

    msgflg:消息队列的建立标志和访问权限。msgflg 的低位用来确定消息队列的访问权限。

 

  www.2cto.com  

查询文件索引节点号的方法是: ls -i

如果失败,则返回-1:errno=EACCESS(权限不允许)

        IPC_RMID:删除消息队列。

 

返回说明:

参数:

        如果设置为 IPC_NOWAIT,则在消息队列已满时不发送消息并且调用进程立即返回错误信息EAGAIN。

    char mtext[1];  /* 消息文本 */


    long mtype;     /* 消息类型,必须 > 0 */

        如果设置为 0,则调用进程阻塞直至消息队列不为满。

ENOMEM(创建队列时内存不够)

 

 

    msgtyp < 0:收取第一条最低类型(小于或等于 msgtyp 的绝对值)的消息。 

成功执行时,msgrcv()返回0, 失败返回-1

        IPC_INFO:读取消息队列基本情况。此命令等同于 ipcs 命令。

    msqid:消息队列的标识符。

EIDRM(队列标志为删除)

        

        IPC_STAT:读取消息队列属性。取得此队列的msqid_ds 结构,并将其存放在buf指向的结构中。 


本文由彩世界开奖app官网发布于彩世界开奖app官网,转载请注明出处:linux 进程间通信机制(IPC机制)一消息队列【彩

关键词: Linux C C语言