System V 消息队列

     首先我们来看操纵System V消息队列的函数。

    (1)msgget函数用于创建一个新的消息队列或访问一个已存在的消息队列

   #include<sys/msg.h>

   int msgget(key_t key,int oflag);

  返回值是一个整数标识符。它是基于指定的key值产生的,而key即可以是ftok的返回值,也可以是常值IPC_PRIVATE.


   oflag表示读写权限值的组合。


    (2)msgsnd函数:

   使用msgget函数打开一个消息队列后,我们使用msgsnd往其上放置一个消息

  #include<sys/msg.h>

  int msgsnd(int msqid,const void *ptr,size_t length,int flag)

其中msqid是由msgget返回的标识符。ptr是一个结构指针,该结构具有如下的模板:

       struct msgbuf{

               long  mtype;

               char mtext[1];

        };

length参数以字节为单位指定待发消息的长度。这是位于长整数消息之后的用户自定义数据的长度。该长度可以是0.

flag参数即可以是0,也可以是IPC_NOWAIT。IPC_NOWAIT标志使得msgsnd调用非阻塞:如果没有存放新消息的可用空间,该函数就马上返回。

(3)msgrev函数:

    使用msgrev函数从某一个消息队列中读出一个消息。

    #include<sys/msg.h>

    ssize_t  msgrev(int  msqid,void *ptr,size_t length,long type,int flag)

    其中ptr参数指定所接收的消息存放的位置,

   length指定了由ptr指向的缓冲区中的数据部分的大小。这是该函数能返回的最大数据量。该长度不包括长整型类型字段。

   type指定希望从所给定的队列中读取什么样的消息:

        (1)如果type为0,那就返回该队列中的第一个消息。

        (2)如果type大于0,那就返回其类型值为type的第一个消息。

        (3)如果type小于0,那就返回其类型值小于或等于type参数的绝对值的消息中类型值最小的第一个参数。

(4)msgctl函数:
      提供在一个消息队列上的各种控制操作。

   #include<sys/msg.h>

  int  magctl(int msqid,int cmd,struct misqid_ds *buff)

  返回:成功为0,错误为-1

现在我们用消息队列实现客户端-服务器的例子,服务器获得路径名,将文件的内容返回到客户端。

我们先来看客户端的程序:

#include"uitil.h"

int main(int argc,char* argv[])
{
    int readid,writeid;
    
    writeid = msgget(MQ_KEY1,0);
    if(writeid == -1){
        cout << "writeid error." << endl;
        exit(1);
    }

    readid = msgget(MQ_KEY2,0);
    if(readid == -1){
        cout << "readid error." << endl;
        exit(1);
    }

    client(readid,writeid);

    msgctl(readid,IPC_RMID,NULL);
    msgctl(writeid,IPC_RMID,NULL);

    return 0;
}

服务器程序:
#include"uitil.h"

int main(int argc,char*argv[])
{
    int readid,writeid;
    
    readid = msgget(MQ_KEY1,SVMSG_MODE | IPC_CREAT);
    if(readid == -1){
        cout << "readid msgget error." << endl;
        exit(1);
    }
    writeid = msgget(MQ_KEY2,SVMSG_MODE | IPC_CREAT);

    if(writeid == -1){
        cout << "writeid msgget error." << endl;
        exit(1);
    }
    server(readid,writeid);

    return 0;
}

头文件加一些函数 uitil.h


#pragma once

#include<iostream>
#include<stdio.h>
#include<sys/msg.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
using namespace std;

#define MQ_KEY1 1234L
#define PIPE_BUFF 4096
#define MQ_KEY2 2345L 
#define MAXMESGDATA (PIPE_BUFF - 2 * sizeof(long))
#define MESGHDRSIZE (sizeof(struct mymesg) - MAXMESGDATA)
#define MSG_R 0400 //read permission
#define MSG_W 0200 //write permission
#define SVMSG_MODE (MSG_R | MSG_W | MSG_R >> 3 | MSG_R >> 6)

struct mymesg{
    long mesg_len;
    long mesg_type;
    char mesg_data[MAXMESGDATA];
};

ssize_t mesg_send(int id,struct mymesg *mptr)
{
    return (msgsnd(id,&(mptr->mesg_type),mptr->mesg_len,0));
}

ssize_t mesg_recv(int id,struct mymesg *mptr)
{
    ssize_t n;
    n = msgrcv(id,&(mptr->mesg_type),MAXMESGDATA,mptr->mesg_type,0);
    mptr->mesg_len = n;

    return (n);
}

void client(int readfd,int writefd)
{
    size_t len;
    ssize_t n;
    struct mymesg mesg;

    //将客户端输入的路径名写入mesg.mesg_data中
    fgets(mesg.mesg_data,MAXMESGDATA,stdin);
    len = strlen(mesg.mesg_data);
    if(mesg.mesg_data[len - 1] == '\n'){
        len--;
    }
    mesg.mesg_len = len;
    mesg.mesg_type = 1;
    //将mesg的内容放入队列MQ_KEY1
    mesg_send(writefd, &mesg);

    //客户端从MQ_KEY2中读出文件的内容进行显示
    while((n = mesg_recv(readfd,&mesg)) > 0){
        write(STDOUT_FILENO,mesg.mesg_data,n);
    }
}

void server(int readfd,int writefd)
{
    FILE *fp;
    ssize_t n;
    struct mymesg mesg;

    mesg.mesg_type = 1;
    //服务器从MQ_KEY1队列中的消息读入到mesg中
    //其中mesg为路径名
    if((n = mesg_recv(readfd,&mesg)) == 0){
        cout << "pathname missing." << endl;
        exit(1);
    }
    mesg.mesg_data[n] = '\0';
    

    if((fp = fopen(mesg.mesg_data,"r")) == NULL){
        snprintf(mesg.mesg_data + n,sizeof(mesg.mesg_data) - n,
                 ": cant't open,%s\n",strerror(errno));
        mesg.mesg_len = strlen(mesg.mesg_data);
        mesg_send(writefd,&mesg);
    }else{
        //当以只读方式打开文件成功时,将文件的内容放入队列MQ_KEY2
        while(fgets(mesg.mesg_data,MAXMESGDATA,fp) != NULL){
            mesg.mesg_len = strlen(mesg.mesg_data);
            mesg_send(writefd,&mesg);
        }
        fclose(fp);
    }
    
    mesg.mesg_len = 0;
    mesg_send(writefd,&mesg);
}

我们在命令行启动服务器,然后再启动客户端,其执行结果如下:

第一种情况为test文件存在时,服务器将文件的返回到客户端。

第二种情况为文件不存在时,服务器将返回错误。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值