(P27)system v消息队列

1.单个消息队列实现回射服务器

  • 队列复用功能:客户端——>服务器端,服务器端——>客户端端

  • 客户1:只接收类型为1234的消息,客户2只接收类型为9876的消息
    在这里插入图片描述

  • 单个队列的死锁现象: 当多个客户端往发送请求,将队列堵满了,服务器不能够应答,客户端在等待服务器回射数据回来,此时会产生死锁。

  • eg服务端程序:NetworkProgramming-master (1)\NetworkProgramming-master\P27msgsrv.c

//
// Created by wangji on 19-8-12.
//

// p25 system v消息队列(三)回射服务器端

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

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>//memset函数的头文件

#define ERR_EXIT(m) \
        do \
        { \
             perror(m); \
             exit(EXIT_FAILURE);    \
        } while (0);


#define MSGMAX 8192

struct msgbuf 
{
    long mtype;       /* message type, must be > 0 */
    char mtext[msgbuf];    /* message data */
};

void echo_srv(int msgid)
{
    struct msgbuf msg;
    int n;
    int type;
    memset(&msg, 0, sizeof(msgbuf));
    while (1)
    {
        if ((n = msgrcv(msgid, &msg, MSGMAX, 1, 0)) < 0)//不停的接收类型=1的消息,0表示以阻塞的方式接收
        {
            ERR_EXIT("msgsnd");
        }

        //解析的来自客户端的pid+回射行line
        type = *((int*)msg.mtext);//取出前4个字节
        msg.mtype = type;

        //前4个字节是pid
        fputs(msg.mtext+4, stdout);

        if (msgsnd(msgid, &msg, n, 0) < 0)
        {
            ERR_EXIT("msgsnd");
        }
        //memset(&msg, 0, sizeof(msgbuf));
    }

}

int main(int argc, char** argv)
{
    int msgid;
    msgid = msgget(1234, IPC_CREAT|0666);
    if (msgid == -1)
    {
        ERR_EXIT("msgget");
    }

    echo_srv(msgid);

    return 0;
}
  • eg客户端程序:NetworkProgramming-master (1)\NetworkProgramming-master\P27msgcli.c
//
// Created by wangji on 19-8-12.
//

// p25 system v消息队列(三)回射客户端

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

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m) \
        do \
        { \
             perror(m); \
             exit(EXIT_FAILURE);    \
        } while (0);

#define MSGMAX 8192

#define MSGMAX 8192

struct msgbuf 
{
    long mtype;       /* message type, must be > 0 */
    char mtext[MSGMAX];    /* message data */
};


int echocli(int msgid)
{
    struct msgbuf msg;
    memset(&msg, 0, sizeof(msgbuf));
    int pid = getpid();
    msg.mtype = 1;//客户端给服务器段发送的消息类型总是=1
    *((int*)msg.mtext) = pid;//msg.mtext前4个字节是pid
    int n;
    //msg.mtext + 4,表示前4个字节是pid
    while (fgets(msg.mtext + 4, MSGMAX, stdin) != NULL)//不停的从键盘中获取1行数据
    {
        //msgsnd(msgid, &msg,4 + strlen(4+msg.mtext), 0)也对,客户端发送的是:pid+回射行line
        if (msgsnd(msgid, &msg, sizeof(long) + strlen(msg.mtext), 0) < 0)
        {
            ERR_EXIT("msgsnd");
        }
        
        //前4个字节不需要清空,用以保存pid
        memset(msg.mtext+4, 0, sizeof(msg.mtext + 4));

        if ((n = msgrcv(msgid, &msg, MSGMAX, pid, 0)) < 0)//接收类型是pid的消息
        {
            ERR_EXIT("msgsnd");
        }
        fputs(msg.mtext + 4, stdout);
        memset(msg.mtext + 4, 0, sizeof(msg.mtext + 4));
    }


}

int main(int argc, char** argv)
{
    int msgid;
    msgid = msgget(1234, 0);
    if (msgid == -1)
    {
        ERR_EXIT("msgget");
    }

    echocli(msgid);



    return 0;
}

  • 测试结果如下:
    在这里插入图片描述
    在这里插入图片描述

2.多个队列解决单个队列的死锁问题

  • 多个队列解决死锁现象
    (1)当一个客户端创建时,同时创建一个私有的队列;
    (2)当客户端往服务器端发送消息时,会将私有队列的标识符传递给服务器端,以便服务器端能够向私有队列填充数据;
    (3)服务器端收到消息后,会fork一个子进程来将消息回射到客户端,子进程将消息填充到私有队列中;

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章