线程之间的使用消息对列和进程之间使用消息对列

消息队列是消息的链表,存放在内核中并由消息队列标识符表示。
消息队列提供了一个从一个进程向另一个进程发送数据块的方法,每个数据块都可以被认为是有一个类型,接受者接受的数据块可以有不同的类型

1.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

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);

2.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

3.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];
};

4.msgrcv

功能:是从一个消息队列接受消息
原型:

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

参数:
msgsz: 消息数据的长度

msgtyp: 决定从队列中返回哪条消息:
msgtyp=0 返回消息队列中第一条消息
msgtyp>0 返回消息队列中等于mtype 类型的第一条消息。
msgtyp<0 返回mtype<=type 绝对值最小值的第一条消息。

msgflg 为0表示阻塞方式,设置IPC_NOWAIT 表示非阻塞方式
返回值:
msgrcv 调用成功返回接收的数据长度,不成功返回-1。

注意

1:在发送函数中使用的结构,如下:

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

其中第一个长整型数据表示发送消息类型,必须大于0

2:接收函数有一个参数成员long msgtyp,可以这样理解。如果msgtyp = 0,则接收所有发送类型的的数据,如果msgtyp >= 1 ,则只接受和msgtyp类型一样的发送数据。

3:发送和接收都有一个参数是size_t msgsz,这个大小为要传输的结构体的大小减去第一个long型数据之后的大小。

线程之间使用消息队列

在主线程中创建一个子线程,主线程中不停的向消息队列中发送数据,子线程不停的从消息队列中接收数据

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

#define MAX_TEXT 16

int msgid = -1;
/*消息对列使用的固定格式的结构体,第二个成员是消息对列传递信息的数组*/
struct msg_st{
        long int msg_type;
        char text[MAX_TEXT];
};
/*子线程函数,用于接收数据,其中msgid要与主线程获取的一致*/
void *rev_func(void *data){

        struct msg_st data1;
        long int msgtype = 0;
        key_t key = ftok("/home/kayshi/code", 0x666);
        printf("key = %d\n", key);
        msgid = msgget(key, 0666|IPC_CREAT);
        printf("rev : msgid = %d\n", msgid);
        while(1) {
                printf("wait for data:\n");
                /*接收数据,会刚在data1的数组中*/
                if(msgrcv(msgid, (void *)&data1, MAX_TEXT, msgtype, 0) == -1) {
                        fprintf(stderr, "msgget failed error: %d\n", errno);
                        exit(EXIT_FAILURE);
                }   
    
                printf("rec:%s\n", data1.text);
        }   
}

int main(int argc, char **argv)
{
        struct msg_st data;
        char buffer[MAX_TEXT];
        int msgid = -1;
        pthread_t thread_id;
        char *p= "this is a test\n";

//      strncpy(data.text, "hello", 5);
//      printf("send data: %s\n", data.text);
        data.msg_type = 1;
        key_t key = ftok("/home/kayshi/code", 0x666);/*利用ftok生成key值*/
        printf("key = %d\n", key);
        msgid = msgget(key, 0666|IPC_CREAT);/*用key值生成消息队列标识码*/
        printf("main : msgid = %d\n", msgid);
        if(msgid < 0) {
                fprintf(stderr, "msgget failed error: %d\n", errno);
                exit(EXIT_FAILURE);
        }
        /*创建一个子线程用来接收进程消息*/
        int ret = pthread_create(&thread_id, NULL, rev_func, (void *)p);
        if(ret !=0 )
                printf("thread create failed\n");
        while(1) {
                printf("Enter some text:");
                fgets(data.text, MAX_TEXT, stdin);/*获取标准输入的字符串,并存于data的数组中*/
                printf("send begin!\n");
                /*向消息队列中发送数据,注意地第二个参数是指向结构体的指针*/
                if(msgsnd(msgid, (void *)&data, MAX_TEXT, 0) == -1){
                        fprintf(stderr,"msg_snd failed\n");
                        exit(EXIT_FAILURE);
                }
                printf("send sucess!\n");
                if(strncmp(buffer, "end", 3) == 0)
                {
                        break;
                }
                sleep(1);
        }
        exit(EXIT_SUCCESS);
}

由于创建了线程,编译的时候指定第三库-pthread,否则会报错

 gcc -o msg msg.c -pthread

进程之间使用消息队列

与线程调用的方法一致,只不过需要两个代码,分别运行

接收端

msgreceive.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/msg.h>
#include<errno.h>
#define MAX_TEXT 512
struct msg_st{
        long int msg_type;
        char text[MAX_TEXT];
};

int main(int argc, char **argv){
        int msgid = -1; 
        struct msg_st data;
        long int msgtype = 0;
    
        key_t key = ftok("/home/kayshi/", 0x0666);    
        printf("key = %d\n", key);
        msgid = msgget(key, 0666 | IPC_CREAT);
        if (msgid == -1){
                fprintf(stderr, "msgget failed witdth error: %d\n", errno);
                exit(EXIT_FAILURE);
        }   

        printf("receive data:\n");
        while(1) {
                if (msgrcv(msgid, (void*)&data, MAX_TEXT, msgtype, 0) == -1) {
                        fprintf(stderr, "msgrcv failed width: %d\n", errno);
                }   

                printf("You wrote:%s", data.text);

                if(strncmp(data.text, "end", 3) == 0)
                {   
                        break;
                }   
        }   
    
        if(msgctl(msgid, IPC_RMID, 0) == -1) 
        {   
                fprintf(stderr, "msgctl failed width: %d\n", errno);
        }
        exit(EXIT_SUCCESS);
}

发送端

msgsend.c

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

#define MAX_TEXT 512

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

int main(int argc, char **argv)
{
        struct msg_st data;
        char buffer[MAX_TEXT];
        int msgid = -1; 

        key_t key = ftok("/home/kayshi/", 0x6666);
        printf("key = %d\n", key);
        msgid = msgget(key, 0666|IPC_CREAT);
        if(msgid == -1) {
                fprintf(stderr, "msgget failed error: %d", errno);
                exit(EXIT_FAILURE);
        }   
    
        while(1) {
                printf("Enter some text: \n");
                fgets(data.text, MAX_TEXT, stdin);
                data.msg_type = 1;
    
                if(msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1){
                        fprintf(stderr,"msg_snd failed\n");
                        exit(EXIT_FAILURE);
                }   
                if(strncmp(buffer, "end", 3) == 0)
                {   
                        break;
                }
                                sleep(1);
        }
        exit(EXIT_SUCCESS);
}

分别编译并开两个客户端执行
执行接收端

kayshi@ubuntu:~/code/message_queue$ gcc -o msgreceive msgreceive.c 
kayshi@ubuntu:~/code/message_queue$ gcc -o msgsend msgsend.c 
kayshi@ubuntu:~/code/message_queue$ ./msgreceive 
key = 1711356889
receive data:

执行发送端,并在发送端写入数据hello

root@ubuntu:/home/kayshi/code/message_queue# ./msgsend 
key = 1711356889
Enter some text: 
hello
Enter some text: 

查看接收端是否有数据接收

kayshi@ubuntu:~/code/message_queue$ ./msgreceive 
key = 1711356889
receive data:
You wrote:hello

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值