Linux通讯(消息队列)

消息队列

消息队列就是一个消息的链表。可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息。消息队列是随内核持续的。

在linux中我们可以通过下面的指令来查看消息队列

ipcs -q

也可以通过下面的命令删除消息队列

ipcrm -q 【msgid】

一、消息队列相关函数

1、msgget函数

函数原型

int msgget(key_t key,int msgflg);

所需头文件

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

返回值
成功:返回所创建的消息队列的文件描述符
失败:-1

参数
key标识消息队列的键值(就像文件的标识是文件名):0 / IPC_PRIVATE
msgflg即为对消息队列的权限还包含有效的标志,包括IPC_CREAT 和IPC_EXCL,他们的功能与open()的O_CREAT和O_EXCL相当
IPC_CREAT 如果消息队列不存在,则创建一个消息队列,否则直接打开已存在的
IPC_EXCL 只有在消息队列不存在的时候,新的消息队列才建立,否则就产生错误

其中,当key的取值为IPC_PRIVATE,则函数msgget()将创建一块新的消息队列;通过这种方式创建的消息队列,一般用来亲缘关系的进程间通信,非亲缘关系之间我们一般是通过ftok这个函数获取键值

(1)当key为ftok所获取的

ftok函数原型

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

所需头文件

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

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

参数
pathname就是你指定的文件名(已经存在的文件名),一般使用当前目录
proj_id是子序号,它是一个8bit的整数。即范围是0~255

(2)当key为IPC_PRIVATE时如

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

int main()
{
    int msgid = msgget(IPC_PRIVATE,0777);
    if(msgid == -1)
    {
        printf("creat message queue fail\n");
        return -1;
    }
    else
    {
        printf("creat message queue success\n");
    }
    system("ipcs -q");
    return 0;
}

2、msgsnd(消息添加到队列中)

函数原型

int msgsnd(int msgid,const void *msgp,size_t msgze,int msgflg);

所需头文件

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

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

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

例如:

#include <stdio.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <string.h>
#include <sys/ipc.h>

typedef struct msgbuf
{
    long type;
    char buf[120];
}msgbuf;

int main()
{
    //creat message queue
    int msgid = msgget(IPC_PRIVATE,0777);
    if(msgid == -1)
    {
        printf("creat message queue fail\n");
        return -1;
    }
    else
    {
        printf("creat message queue success,msgid == %d\n",msgid);
    }
    system("ipcs -q");
    
    //message queue send
    struct msgbuf msg;
    msg.type = 100;
    memset(msg.buf,120,0);
    printf("input : ");
    fgets(msg.buf,120,stdin);
    int sndret = msgsnd(msgid,(void *)&msg,strlen(msg.buf),0);
    if(sndret == -1)
    {
        printf("message queue send fail\n");
        return -3;
    }
    else
    {
        printf("message queue send success\n");
    }
    
    return 0;
}


3、msgrcv(从消息队列接受消息)

函数原型

ssize_t msgrcv(int msgid,void *msgp,size_t msgze,long msgtyp,int msgflg);

所需头文件

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

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

参数
同msgsnd

例如:

#include <stdio.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <string.h>
#include <sys/ipc.h>

typedef struct msgbuf
{
    long type;
    char buf[120];
}msgbuf;

int main()
{
    //creat message queue
    int msgid = msgget(IPC_PRIVATE,0777);
    if(msgid == -1)
    {
        printf("creat message queue fail\n");
        return -1;
    }
    else
    {
        printf("creat message queue success,msgid == %d\n",msgid);
    }
    system("ipcs -q");
    
    //message queue send
    struct msgbuf msg;
    msg.type = 100;
    printf("input : ");
    fgets(msg.buf,120,stdin);
    int sndret = msgsnd(msgid,(void *)&msg,strlen(msg.buf),0);
    if(sndret == -1)
    {
        printf("message queue send fail\n");
        return -3;
    }
    else
    {
        printf("message queue send success\n");
    }
    
    //receive message queue
    struct msgbuf rcvbuf;
    memset(rcvbuf.buf,120,0);
    ssize_t rcvret = msgrcv(msgid,(void *)&rcvbuf,120,100,0);
    printf("receive : %s",rcvbuf.buf);
    printf("rcvert = %d\n",rcvret);

    return 0;
}

4、msgctl(消息队列的控制函数)

函数原型

int msgctl(int msgid,int cmd,struct msgid_ds *buf);

所需头文件

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

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

参数
msgid : 消息队列标识ID
cmd :
IPC_STAT得到消息队列的状态
IPC_SET改变消息队列的状态
IPC_RMID删除消息队列
buf :是一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变消息队列的状态,用这个结构体指定,如果要删除消息队列则设置为NULL即可

例如:

#include <stdio.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/types.h>

int main()
{
    int msgid = msgget(IPC_PRIVATE,0777);
    if(msgid == -1)
    {
        printf("creat message queue fail\n");
        return -1;
    }
    else
    {
        printf("creat message queue success,msgid == %d\n",msgid);
    }
    system("ipcs -q");

    int ctlret = msgctl(msgid,IPC_RMID,0);
    if(ctlret == -1)
    {
        printf("msgctl msgid : %d  fail\n",msgid);
        return -2;
    }
    else
    {
        printf("msgctl msgid : %d  success\n",msgid);
    }
    system("ipcs -q");

    return 0;
}

二、进程间通讯

1、有亲缘关系通讯:

#include <stdio.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>

typedef struct msgbuf
{
    long type;
    char buf[120];
}msgbuf;

int main()
{
    int msgid = msgget(IPC_PRIVATE,0777);
    if(msgid == -1)
    {
        printf("creat message queue fail\n");
        return -1;
    }
    else
    {
        printf("creat message queue success , msgid = %d\n",msgid);
        system("ipcs -q");
    }

    pid_t pid = fork();
    if(pid<0)
    {
        printf("fork fail\n");
        return -2;
    }

    if(pid == 0)
    {
        struct msgbuf rcvbuf;
        while(1)
        {
            memset(rcvbuf.buf,0,120);
            msgrcv(msgid,(void *)&rcvbuf,120,100,0);
            printf("read message from message queue : %s",rcvbuf.buf);
            if(strncmp(rcvbuf.buf,"end",3) == 0)
            {
                break;
            }
        }
    }

    if(pid > 0)
    {
        struct msgbuf sndbuf;
        sndbuf.type = 100;
        while(1)
        {
            fgets(sndbuf.buf,120,stdin);
            printf("write message to message queue : %s",sndbuf.buf);
            msgsnd(msgid,(void *)&sndbuf,strlen(sndbuf.buf),0);
            if(strncmp(sndbuf.buf,"end",3) == 0)
            {
                break;
            }
        }
    }
    int ctlret = msgctl(msgid,IPC_RMID,NULL);
    if(ctlret == -1)
    {
        printf("delete message queue fail\n");
        return -3;
    }
    else
    {
        printf("delete message queue success , msgid : %d\n",msgid);
        system("ipcs -q");
    }

    return 0;
}

2、无亲缘关系的进程通讯

客户端和服务端的通讯

服务端:

#include <stdio.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <string.h>

typedef struct msgbuf
{
    long type;
    char buf[120];

}msgbuf;

int main()
{
    key_t key = ftok(".",123);
    if(key<0)
    {
        printf("creat key fail\n");
        return -1;
    }
    else
    {
        printf("creat key success, key = %d\n",key);
    }

    int msgid = msgget(key,IPC_CREAT|0770);
    if(msgid == -1)
    {
        printf("creat message queue fail\n");
        return -2;
    }
    else
    {
        printf("creat message queue success, msgid = %d\n",msgid);
    }
    
    pid_t pid = fork();
    if(pid<0)
    {
        printf("creat fork fail\n");
        return -3;
    }

    if(pid > 0)
    {
        struct msgbuf serbuf1;
        serbuf1.type = 100;
        while(1)
        {
            fgets(serbuf1.buf,120,stdin);
            printf("ser : %s",serbuf1.buf);
            msgsnd(msgid,(void *)&serbuf1,strlen(serbuf1.buf),0);
        }
    }
    if(pid == 0)
    {
        struct msgbuf serbuf2;
        while(1)
        {
            memset(serbuf2.buf,0,120);
            msgrcv(msgid,(void *)&serbuf2,120,200,0);
            printf("cli : %s",serbuf2.buf);
        }
    }
    return 0;
}

客户端

#include <stdio.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <string.h>

typedef struct msgbuf
{
    long type;
    char buf[120];

}msgbuf;

int main()
{
    key_t key = ftok(".",123);
    if(key<0)
    {
        printf("creat key fail\n");
        return -1;
    }
    else
    {
        printf("creat key success, key = %d\n",key);
    }

    int msgid = msgget(key,IPC_CREAT|0770);
    if(msgid == -1)
    {
        printf("creat message queue fail\n");
        return -2;
    }
    else
    {
        printf("creat message queue success, msgid = %d\n",msgid);
    }
    
    pid_t pid = fork();
    if(pid<0)
    {
        printf("creat fork fail\n");
        return -3;
    }
    
    if(pid > 0)
    {
        struct msgbuf clibuf1;
        memset(clibuf1.buf,0,120);
        while(1)
        {
            msgrcv(msgid,(void *)&clibuf1,120,100,0);
            printf("ser : %s",clibuf1.buf);
        }
    }

    if(pid == 0)
    {
        struct msgbuf clibuf2;
        clibuf2.type = 200;
        while(1)
        {
            memset(clibuf2.buf,0,120);
            fgets(clibuf2.buf,120,stdin);
            printf("cli : %s",clibuf2.buf);
            msgsnd(msgid,(void *)&clibuf2,strlen(clibuf2.buf),0);
        }
    }
    return 0;
}

发布了28 篇原创文章 · 获赞 0 · 访问量 995

猜你喜欢

转载自blog.csdn.net/wfea_lff/article/details/104087676