欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

一起talk C栗子吧(第九十七回:C语言实例--使用消息队列进行进程间通信一)

程序员文章站 2022-04-18 22:37:23
各位看官们,大家好,上一回中咱们说的是使用共享内存进行进程间通信的例子,这一回咱们说的例子是:使用消息队列进行进程间通信。闲话休提,言归正转。让我们一起talk C栗子吧!...


各位看官们,大家好,上一回中咱们说的是使用共享内存进行进程间通信的例子,这一回咱们说的例子是:使用消息队列进行进程间通信。闲话休提,言归正转。让我们一起talk C栗子吧!

消息队列是SystemV IPC结构这种抽象概念的一种具体对象,这点和共享内存一样。消息队列提供了一个队列供不同的进程使用,进程之间可以通过该队列传递数据,进而实现进程间的通信。

在介绍消息队列的使用方法之前,我们先介绍几个函数,这些函数都是用来操作消息队列的。

msgget函数

int msgget(key_t key,int msgflag)

该函数用来创建一个新的消息队列或者获取已经存在的消息队列。

第一个参数是键值,通过它来操作IPC在内核中的结构,也就是消息队列在内核中的结构;(前面章回中介绍过) 第二个参数是消息队列的权限标记,该权限和文件权限一样; 该函数运行成功时返回消息队列标识符,否则返回-1;我们可以通过该标识符使用消息队列;

msgsnd函数

int msgsnd(int msg_id, const void *msg_ptr,size_t msg_sz,int msgflg)

该函数用来把消息添加到消息队列中,这样进程就可以从消息队列中获取消息了;

在使用该函数的时候,我们需要自己定义一个消息的类型,并且计算出该类型的内存空间。消息的类型可以依据程序需要来定义,常见的是定义一个结构体类型。不过类型中的第一个成员必须是一个long int类型的成员,该成员用来确定消息的类型。

第一个参数是消息队列的标识符,通过msgget函数可以获得; 第二个参数是一个指针,该指针指向准备添加到消息队列中消息; 第三个参数是一个int类型的值,表示准备添加到消息队列中消息的大小; 第四个参数是一个位标记,该标记用来控制消息队列已满或者达到系统限制时的动作。 该函数运行成功时返回0,否则返回-1;

在使用该函数的时候,第四个参数通常为IPC_NOWAIT,表示消息队列已满后函数不发消息到消息队列中,并且立刻返回-1.如果没有设置该标记,那么消息队列已满后先把以送消息的进程挂起,直到消息到消息队列中有空间了,它再发送消息到消息队列中。

msgrcv函数

int msgrcv(int msgid,void *msg_ptr,size_t msg_sz,long int msgtype,int msgflg)

该函数用来从消息队列中获取消息或者说接收消息;

第一个参数是消息队列的标识符,通过msgget函数可以获得; 第二个参数是一个指针,该指针指向准备从消息队列中获取的消息; 第三个参数是一个int类型的值,表示获取消息的大小; 第四个参数是一个long int类型的值,表示接收消息的优先级; 第五个参数是一个位标记,该标记用来控制消息队列中没有消息供接收时的动作。 该函数运行成功时返回接收到消息的字节数,否则返回-1;

在使用该函数数,第五个参数的值和msgsnd函数中第四个参数的值一样,而且函数的动作也类似,只不过从发送消息转换为接收消息。该函数的第四个参数通常为0,表示按照消息的发送顺序接收消息;
如果它的值为n(n>0),表示接收类型值为n的这一类消息;
如果它的值为-n(n>0),表示接收类型值为等于或者小于n的这一类消息;
这里说的类型值就是我们定义消息类型中的第一个成员。

msgctl函数

int msgctl(int msg_id, int cmd,struct msgid_ds *buf)

该函数用来对消息队列进行相关操作,常用的操作是删除消息队列;

第一个参数是消息队列的标识符,通过msgget函数可以获得; 第二个参数是一个命令,表示对消息队列的操作,只有三个命令供使用:IPC_STAT,IPC_SET和IPC_RMID; 第三个参数是一个结构体指针,该结构体中有消息队列的权限和所有者等信息; 该函数运行成功时返回0,否则返回-1;

我们通常使用该函数删除消息队列,这时候需要给第二个参数赋值为IPC_RMID,表示删除消息队列,第三参数可以为空指针。第二个参数的另外两个命令:IPC_STAT表示把第三个参数中的内容和消息队列关联起来;IPC_SET表示把第三个参数中的内容设置为消息队列的值。第三个参数的类型,我们在前面章回中提起过,它和SystemV IPC的结构类似,除了必须有的成员外,它还有自己特有的成员。

该函数的用法和咱们在前面章回中介绍过的shmctl函数用法类似,大家可以进行对比。

我从源代码中找到了第三个参数的类型,详细的定义如下:(位于linux-4.0.3/include/linux/msg.h文件中)

struct msg_queue {
    struct kern_ipc_perm q_perm;
    time_t q_stime;         /* last msgsnd time */
    time_t q_rtime;         /* last msgrcv time */
    time_t q_ctime;         /* last change time */
    unsigned long q_cbytes;     /* current number of bytes on queue */
    unsigned long q_qnum;       /* number of messages in queue */
    unsigned long q_qbytes;     /* max number of bytes on queue */
    pid_t q_lspid;          /* pid of last msgsnd */
    pid_t q_lrpid;          /* last receive pid */

    struct list_head q_messages;
    struct list_head q_receivers;
    struct list_head q_senders;
};

各位看官,关于使用消息队列进行进程间通信的例子咱们就说到这里。欲知后面还有什么例子,且听下回分解 。