System V 消息队列 (每个客户一个队列)

来源:互联网 发布:数据库访问缓存 编辑:程序博客网 时间:2024/06/05 10:41

    今天将之前的一个服务器和多个客户端的例子改成给去往服务器的所有客户请求使用一个队列,给每个客户使用一个队列接收去往各个客户的服务器应答。

     下面给出这样的设计:

    服务器的队列有一个对客户来说众所周知的键,但是各个客户以IPC_PRIVATE键创建各自的队列,这里并未随请求传递本进程id,而是由每个客户把自己的私用队列的标识符传递给服务器,服务器把自己的应答发送到由客户指出的队列中。我们还以并发服务器模型编写这个服务器程序,给每个客户fork一次。。。

首先给出客户端的代码:

#include"uitil.h"int main(int argc,char*argv[]){    int readid,writeid;    //打开服务器创建的MQ_KEY1        writeid = msgget(MQ_KEY1,0);    if(writeid == -1){        cout << "msgget error." << endl;        exit(1);    }    //客户端创建自己的消息队列    readid = msgget(IPC_PRIVATE,SVMSG_MODE | IPC_CREAT);    if(readid == -1){        cout << "msgget error." << endl;        exit(1);    }        client(readid,writeid);    //客户端删除自己创建的消息队列    msgctl(readid,IPC_RMID,NULL);    return 0;}

服务器端代码:
#include"uitil.h"int main(int argc,char*argv[]){    int msqid;    //服务器创建消息队列MQ_KEY1        msqid = msgget(MQ_KEY1,SVMSG_MODE | IPC_CREAT);    if(msqid == -1){        cout << "msgget error." << endl;        exit(1);    }    server(msqid,msqid);    return 0;}

头文件uitil.h:

#pragma once#include<iostream>#include<stdio.h>#include<stdlib.h>#include<sys/msg.h>#include<string.h>#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<signal.h>#include<errno.h>#include<sys/wait.h>using namespace std;#define MQ_KEY1 1234L#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)#define PIPE_BUFF 4096#define MAXMESGDATA (PIPE_BUFF - 2 * sizeof(long))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 = 0;    return (n);}ssize_t Mesg_recv(int id,struct mymesg *mptr){    ssize_t n;        do{        n = mesg_recv(id,mptr);    }while(n == 1 && errno == EINTR);    if(n == -1){        cout << "mesg_recv error." << endl;    }    return (n);}void sig_chld(int signo){    pid_t pid;    int stat;    while((pid = waitpid(-1,&stat,WNOHANG)) > 0);    return;}void client(int readid,int writeid){    size_t len;    ssize_t n;    char *ptr;    struct mymesg mesg;    //将客户端自己创建的消息队列的msqid + 空格写入mesg_data中    snprintf(mesg.mesg_data,MAXMESGDATA,"%ld ",readid);    len = strlen(mesg.mesg_data);    ptr = mesg.mesg_data + len;    //将路径名也写入客户端创建的消息队列    fgets(ptr,MAXMESGDATA - len,stdin);    len = strlen(mesg.mesg_data);    if(mesg.mesg_data[len - 1] == '\n'){        len--;    }    mesg.mesg_len = len;    mesg.mesg_type  = 1;    //将mesg的内容(msqid + 空格 + 路径名)放置到服务器创建的消息队列中    mesg_send(writeid,&mesg);    //通过客户端私有的消息队列将文件的内容进行显示    while((n = Mesg_recv(readid,&mesg)) >0){        write(STDOUT_FILENO,mesg.mesg_data,n);    }}void server(int readid,int writeid){    FILE *fp;    char *ptr;    ssize_t n;    int pid;    struct mymesg mesg;    void sig_chld(int);    //SIGCHLD在一个进程终止或停止时,将SIGCHLD信号发送给其父进程,按    //系统默认将忽略此信号,如果父进程希望被告知其子进程的这种状态,    //则应进行捕获此信号    signal(SIGCHLD,sig_chld);    for(;;){        mesg.mesg_type = 1;        //通过消息队列MSQ_KEY1将客户端放置在消息队列的消息写入mesg中        //mesg的内容为:客户端的msqid + 空格 + 路径名        if((n = Mesg_recv(readid,&mesg)) == 0){            cout << "pathname missing." << endl;            continue;        }        mesg.mesg_data[n] = '\0';        //ptr用于获取路径名        if((ptr = strchr(mesg.mesg_data,' ')) == NULL){            printf("bogus requset: %s\n",mesg.mesg_data);            exit(1);        }        *ptr++ = 0;        //writeid = 客户端创建的消息队列的msqid         writeid = atoi(mesg.mesg_data);        //创建进程        pid = fork();        if(pid == 0){            //子进程            if((fp = fopen(ptr,"r")) == NULL){                //打开文件失败时,显示错误                snprintf(mesg.mesg_data + n,sizeof(mesg.mesg_data) - n,                         ": can't open,%s\n",strerror(errno));                mesg.mesg_len = strlen(ptr);                memmove(mesg.mesg_data,ptr,mesg.mesg_len);                mesg_send(writeid,&mesg);            }else{                //当打开成功时,将文件的内容发送至客户端私有的消息队列中                while(fgets(mesg.mesg_data,MAXMESGDATA,fp) != NULL){                    mesg.mesg_len = strlen(mesg.mesg_data);                    mesg_send(writeid,&mesg);                }                fclose(fp);            }            mesg.mesg_len = 0;            mesg_send(writeid,&mesg);        }    }}

我们首先启动服务器,程序的执行结果如下:

0 0
原创粉丝点击