• System V 消息队列—复用消息


      消息队列中的消息结构可以由我们自由定义,具备较强的灵活性。通过消息结构可以共享一个队列,进行消息复用。通常定义一个类似如下的消息结构:

    #define MSGMAXDAT     1024
    struct mymsg
    {
        long msg_len;   //消息长度
        long msg_type; //消息类型
        long msg_data[MSGMAXDATA]; //消息内容
    };

     消息结构相关联的类型字段(msg_type)提供了两个特性:

    (1)标识消息,使得多个进程在单个队列上复用消息。

    (2)用作优先级字段,允许接收者以不同于先进先出的某个顺序读出各个消息。

    例子1:每个应用一个队列,可以在多个客户和单个服务器之间复用消息。使用一个消息队列进行通信,由消息类型标识消息是从客户到服务器,还是服务器到客户。通信模型如下:

    按照通信模型编写程序如下:

    公共头文件svmsg.h

    View Code
     1 #ifndef  SVMSG_H
     2 #define  SVMSG_H
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 #include <string.h>
     6 #include <unistd.h>
     7 #include <sys/types.h>
     8 #include <sys/ipc.h>
     9 #include <sys/msg.h>
    10 #include <errno.h>
    11 
    12 #define MSG_R 0400 /* read permission */
    13 #define MSG_W 0200 /* write permission */
    14 #define SVMSG_MODE (MSG_R | MSG_W | MSG_R >>3 | MSG_R >>6)
    15 #define MQ_KEY  1234L
    16 #define MSGMAX  1024
    17 //消息结构
    18 struct mymesg
    19 {
    20     long mesg_len;
    21     long mesg_type;
    22     char mesg_data[MSGMAX];
    23 };
    24 #endif

    客户端程序sysv_client.c

    View Code
     1 #include "svmsg.h"
     2 void client(int ,int);
     3 
     4 int main(int argc,char *argv[])
     5 {
     6     int     msqid;
     7     if((msqid = msgget(MQ_KEY,0)) == -1)
     8     {
     9         perror("megget()");
    10         exit(-1);
    11     }
    12     client(msqid,msqid);
    13     exit(0);
    14 }
    15 
    16 void client(int readfd,int writefd)
    17 {
    18     size_t len;
    19     ssize_t n;
    20     char *ptr;
    21     struct mymesg mesg;
    22     printf("Send request to server.\n");
    23     //set pid to message
    24     snprintf(mesg.mesg_data,MSGMAX,"%ld",(long)getpid());
    25     len = strlen(mesg.mesg_data);
    26     mesg.mesg_data[len] = ' '; //blank
    27     ptr = mesg.mesg_data+len+1;
    28     printf("Enter filename: ");
    29     fgets(ptr,MSGMAX-len,stdin);
    30     len = strlen(mesg.mesg_data);
    31     if(mesg.mesg_data[len-1] == '\n')
    32         len--;
    33     mesg.mesg_len = len;
    34     mesg.mesg_type = 1;
    35     printf("mesg_data is :%s len=%ld\n",mesg.mesg_data, mesg.mesg_len);
    36     if(msgsnd(writefd,&(mesg.mesg_type),mesg.mesg_len,0) == -1)
    37     {
    38         perror("msgsnd() error");
    39         exit(-1);
    40     }
    41     //read from IPC,write to standard output
    42     mesg.mesg_type = getpid();
    43     while( (n = msgrcv(readfd,&(mesg.mesg_type),MSGMAX,mesg.mesg_type,0))>0)
    44     {
    45         write(STDOUT_FILENO,mesg.mesg_data,n);
    46         putchar('\n');
    47     }
    48     if(n == 0 )
    49     {
    50         printf("Read file from server is completed.\n");
    51     }
    52     if(n == -1)
    53     {
    54         perror("msgrcv() error");
    55         exit(-1);
    56     }
    57 }

    服务器程序sysv_server.c

    View Code
     1 #include "svmsg.h"
     2 void server(int ,int);
     3 int main(int argc,char *argv[])
     4 {
     5     int     msqid;
     6     if((msqid = msgget(MQ_KEY,SVMSG_MODE | IPC_CREAT)) == -1)
     7     {
     8         perror("megget()");
     9         exit(-1);
    10     }
    11     server(msqid,msqid);
    12     exit(0);
    13 }
    14 
    15 void server(int readfd,int writefd)
    16 {
    17     FILE            *fp;
    18     char            *ptr;
    19     pid_t           pid;
    20     ssize_t         n;
    21     ssize_t         len;
    22     struct mymesg   mesg;
    23     printf("Waiting for client......\n");
    24     for(; ;)
    25     {
    26         mesg.mesg_type = 1;
    27         if((n = msgrcv(readfd,&(mesg.mesg_type),MSGMAX,mesg.mesg_type,0)) == 0)
    28         {
    29             printf("pathname missing.\n");
    30             continue;
    31         }
    32         mesg.mesg_data[n] = '\0';
    33         printf("Received message from client is: %s\n",mesg.mesg_data);
    34         if ((ptr = strchr(mesg.mesg_data,' ')) == NULL)
    35         {
    36             printf("bogus request: %s\n",mesg.mesg_data);
    37             continue;
    38         }
    39         *ptr++ = 0;
    40         pid = atoi(mesg.mesg_data);
    41         mesg.mesg_type = pid;
    42         //open fiel and read data
    43         if((fp = fopen(ptr,"r")) == NULL)
    44         {
    45             printf("open file failed.sent msg to client\n");
    46             snprintf(mesg.mesg_data+n,sizeof(mesg.mesg_data)-n,": can't open,%s\n",strerror(errno));
    47             mesg.mesg_len = strlen(ptr);
    48             memmove(mesg.mesg_data,ptr,mesg.mesg_len);
    49             if(msgsnd(writefd,&(mesg.mesg_type),mesg.mesg_len,0) == -1)
    50             {
    51                 perror("msgsnd() error");
    52                 exit(-1);
    53             }
    54         }
    55         else
    56         {
    57             printf("open file successed.sent file to client\n");
    58             while(fgets(mesg.mesg_data,MSGMAX,fp) != NULL)
    59             {
    60                 mesg.mesg_len = strlen(mesg.mesg_data);
    61                 if(msgsnd(writefd,&(mesg.mesg_type),mesg.mesg_len,0) == -1)
    62                 {
    63                     perror("msgsnd() error");
    64                     exit(-1);
    65                 }
    66             }
    67             fclose(fp);
    68         }
    69         printf("send compelted.\n");
    70         mesg.mesg_len = 0;
    71         if(msgsnd(writefd,&(mesg.mesg_type),mesg.mesg_len,0) == -1)
    72         {
    73             perror("msgsnd() error");
    74             exit(-1);
    75         }
    76     }
    77 }

    程序测试结果如下所示:

     例子2:每个客户一个队列,将例子1改成所有用户用一个共同的消息队列向服务器发送消息,给每个客户分配一个消息队列,使得服务器对每个客户进行应答。通信模型如下:

    以并发服务器模型编写这个程序,服务器给每个客户fork一个子进程进行处理。程序如下:

    公共头文件svmsg.h和svmsg.c:

    View Code
     1 //svmsg.h file
     2 #ifndef  SVMSG_H
     3 #define  SVMSG_H
     4 #include <stdio.h>
     5 #include <stdlib.h>
     6 #include <string.h>
     7 #include <unistd.h>
     8 #include <signal.h>
     9 #include <sys/types.h>
    10 #include <sys/ipc.h>
    11 #include <sys/msg.h>
    12 #include <errno.h>
    13 
    14 #define MSG_R 0400 /* read permission */
    15 #define MSG_W 0200 /* write permission */
    16 #define SVMSG_MODE (MSG_R | MSG_W | MSG_R >>3 | MSG_R >>6)
    17 #define MQ_KEY  1234L
    18 #define MSGMAX  1024
    19 //message structure
    20 struct mymesg
    21 {
    22     long mesg_len;
    23     long mesg_type;
    24     char mesg_data[MSGMAX];
    25 };
    26 
    27 ssize_t mesg_send(int id,struct mymesg *mptr);
    28 ssize_t mesg_recv(int id,struct mymesg *mptr);
    29 
    30 void    Mesg_send(int id,struct mymesg *mptr);
    31 ssize_t Mesg_recv(int id,struct mymesg *mptr);
    32 #endif
    View Code
     1 //svmsg.c file
     2 #include "svmsg.h"
     3 
     4 ssize_t mesg_send(int id,struct mymesg *mptr)
     5 {
     6     return (msgsnd(id,&(mptr->mesg_type),mptr->mesg_len,0));
     7 }
     8 
     9 ssize_t mesg_recv(int id,struct mymesg *mptr)
    10 {
    11     ssize_t n;
    12     n = msgrcv(id,&(mptr->mesg_type),MSGMAX,mptr->mesg_type,0);
    13     mptr->mesg_len = n;
    14     return n;
    15 }
    16 
    17 void Mesg_send(int id,struct mymesg *mptr)
    18 {
    19     if(mesg_send(id,mptr) == -1)
    20     {
    21         perror("mesg_send() error");
    22         exit(-1);
    23     }
    24 }
    25 ssize_t Mesg_recv(int id,struct mymesg *mptr)
    26 {
    27     ssize_t n;
    28     do
    29     {
    30         n = mesg_recv(id,mptr);
    31     }while(n==-1 && errno == EINTR);
    32     if(n == -1)
    33     {
    34         perror("mesg_recv() error");
    35         exit(-1);
    36     }
    37     return n;
    38 }

    客户端程序如下:

    View Code
     1 #include "svmsg.h"
     2 
     3 void client(int ,int);
     4 
     5 int main(int argc,char *argv[])
     6 {
     7     int    readid,writeid;
     8     if((writeid = msgget(MQ_KEY,0)) == -1)
     9     {
    10         perror("megget()");
    11         exit(-1);
    12     }
    13     if((readid = msgget(IPC_PRIVATE,SVMSG_MODE | IPC_CREAT)) == -1)
    14     {
    15         perror("megget()");
    16         exit(-1);
    17     }
    18     client(readid,writeid);
    19     msgctl(readid,IPC_RMID,NULL);
    20     exit(0);
    21 }
    22 
    23 void client(int readid,int writeid)
    24 {
    25     size_t len;
    26     ssize_t n;
    27     char *ptr;
    28     struct mymesg mesg;
    29     printf("Send request to server.\n");
    30     //set pid to message
    31     snprintf(mesg.mesg_data,MSGMAX,"%d",readid);
    32     len = strlen(mesg.mesg_data);
    33     mesg.mesg_data[len] = ' '; //blank
    34     ptr = mesg.mesg_data+len+1;
    35     printf("Enter filename: ");
    36     fgets(ptr,MSGMAX-len,stdin);
    37     len = strlen(mesg.mesg_data);
    38     if(mesg.mesg_data[len-1] == '\n')
    39         len--;
    40     mesg.mesg_len = len;
    41     mesg.mesg_type = 1;
    42     printf("mesg_data is :%s\n",mesg.mesg_data);
    43     Mesg_send(writeid,&mesg);
    44     printf("Send messge to server successed.\n");
    45     //read from IPC,write to standard output
    46     while( (n = Mesg_recv(readid,&mesg))>0)
    47     {
    48         write(STDOUT_FILENO,mesg.mesg_data,n);
    49         putchar('\n');
    50     }
    51     if(n == 0 )
    52     {
    53         printf("Read file from server is completed.\n");
    54     }
    55 }

    服务器程序如下:

    View Code
     1 #include "svmsg.h"
     2 
     3 void server(int ,int);
     4 void sig_child(int signo);
     5 
     6 int main(int argc,char *argv[])
     7 {
     8     int     msqid;
     9     if((msqid = msgget(MQ_KEY,SVMSG_MODE | IPC_CREAT)) == -1)
    10     {
    11         perror("megget()");
    12         exit(-1);
    13     }
    14     server(msqid,msqid);
    15     exit(0);
    16 }
    17 
    18 void server(int readid,int writeid)
    19 {
    20     FILE            *fp;
    21     char            *ptr;
    22     pid_t           pid;
    23     ssize_t         n;
    24     ssize_t         len;
    25     struct mymesg   mesg;
    26     signal(SIGCHLD,sig_child);
    27     printf("Waiting for client......\n");
    28     for(; ;)
    29     {
    30         mesg.mesg_type = 1;
    31         if((n = Mesg_recv(readid,&mesg)) == 0)
    32         {
    33             printf("pathname missing.\n");
    34             continue;
    35         }
    36         mesg.mesg_data[n] = '\0';
    37         printf("Received message from client is: %s\n",mesg.mesg_data);
    38         if ((ptr = strchr(mesg.mesg_data,' ')) == NULL)
    39         {
    40             printf("bogus request: %s\n",mesg.mesg_data);
    41             continue;
    42         }
    43         *ptr++ = 0;
    44         writeid = atoi(mesg.mesg_data);
    45         if(fork() == 0)
    46         {
    47             //open fiel and read data
    48             if((fp = fopen(ptr,"r")) == NULL)
    49             {
    50                 printf("open file failed.sent msg to client\n");
    51                 snprintf(mesg.mesg_data+n,sizeof(mesg.mesg_data)-n,": can't open,%s\n",strerror(errno));
    52                 mesg.mesg_len = strlen(ptr);
    53                 memmove(mesg.mesg_data,ptr,mesg.mesg_len);
    54                 Mesg_send(writeid,&mesg);
    55             }
    56             else
    57             {
    58                 printf("open file successed.sent file to client\n");
    59                 while(fgets(mesg.mesg_data,MSGMAX,fp) != NULL)
    60                 {
    61                     mesg.mesg_len = strlen(mesg.mesg_data);
    62                     Mesg_send(writeid,&mesg);
    63                 }
    64                 fclose(fp);
    65             }
    66             printf("send compelted.\n");
    67             mesg.mesg_len = 0;
    68             Mesg_send(writeid,&mesg);
    69         }
    70     }
    71 }
    72 
    73 void sig_child(int signo)
    74 {
    75     pid_t   pid;
    76     int     stat;
    77     while ((pid = waitpid(-1,&stat,WNOHANG)) > 0);
    78     return ;
    79 }

    程序测试结果如下:

  • 相关阅读:
    ManyToMany【项目随笔】关于异常object references an unsaved transient instance
    Hibernate映射之OneToOne(第二篇)
    杨辉三角概念及程序实现
    【C语言编程基础】二维数组
    【C++编程基础】——C++生成随机数
    【C++编程基础】——C++指针小结
    【Java编程基础】——Java中Static关键字的使用
    【Java编程基础】Java中this关键字的使用
    【C语言编程基础】递归算法小结
    排序算法之——冒泡排序
  • 原文地址:https://www.cnblogs.com/Anker/p/2850869.html
Copyright © 2020-2023  润新知