• 10.2 消息队列实现的回射服务器


    模型如下:

    服务器:

     1 #include <unistd.h>
     2 #include <sys/types.h>
     3 #include <sys/ipc.h>
     4 #include <sys/msg.h>
     5 
     6 #include <stdlib.h>
     7 #include <stdio.h>
     8 #include <errno.h>
     9 #include <string.h>
    10 
    11 #define ERR_EXIT(m) 
    12         do 
    13         { 
    14                 perror(m); 
    15                 exit(EXIT_FAILURE); 
    16         } while(0)
    17 
    18 
    19 #define MSGMAX 8192
    20 struct msgbuf {
    21     long mtype;       /* message type, must be > 0 */
    22     char mtext[MSGMAX];    /* message data */
    23 };
    24 
    25 
    26 void echo_srv(int msgid)
    27 {
    28     int n;
    29     struct msgbuf msg;
    30     memset(&msg, 0, sizeof(msg));
    31     while (1)
    32     {
    33         if ((n = msgrcv(msgid, &msg, MSGMAX, 1, 0)) < 0)
    34             ERR_EXIT("msgsnd");
    35         
    36         int pid;
    37         pid = *((int*)msg.mtext);
    38 
    39         fputs(msg.mtext+4, stdout);
    40         msg.mtype = pid;
    41         msgsnd(msgid, &msg, n, 0);
    42     }
    43 }
    44 
    45 int main(int argc, char *argv[])
    46 {
    47     int msgid;
    48     msgid = msgget(0x1234, IPC_CREAT | 0666);
    49     if (msgid == -1)
    50         ERR_EXIT("msgget");
    51 
    52     echo_srv(msgid);
    53 
    54     return 0;
    55 }

    客户端:

     1 #include <unistd.h>
     2 #include <sys/types.h>
     3 #include <sys/ipc.h>
     4 #include <sys/msg.h>
     5 
     6 #include <stdlib.h>
     7 #include <stdio.h>
     8 #include <errno.h>
     9 #include <string.h>
    10 
    11 #define ERR_EXIT(m) 
    12         do 
    13         { 
    14                 perror(m); 
    15                 exit(EXIT_FAILURE); 
    16         } while(0)
    17 
    18 #define MSGMAX 8192
    19 struct msgbuf {
    20     long mtype;       /* message type, must be > 0 */
    21     char mtext[MSGMAX];    /* message data */
    22 };
    23 
    24 //思路:
    25 //客户端发给服务器消息类型总是1
    26 //服务器端回给客户端的type是对方进程号
    27 //相当于服务器端 从消息队列中收消息,然后服务器端分类型回复客户端(通过消息队列)
    28 
    29 
    30 //n个进程通过消息队列进行交换
    31 //有没有产生死锁的可能
    32 //n个客户端向服务器发送消息(本质上是向内核消息队列发送消息),若消息队列满了;服务区回射涵时,会阻塞。。造成程序死锁
    33 //即使,非阻塞。。。仍然回阻塞。。
    34 
    35 void echo_cli(int msgid)
    36 {
    37     int n;
    38     int pid;
    39     pid = getpid();
    40     struct msgbuf msg;
    41     memset(&msg, 0, sizeof(msg));
    42     
    43     //消息内容由:自己的pid+键盘输入
    44     *((int*)msg.mtext) = pid;
    45     //消息类型 1
    46     msg.mtype = 1;
    47     
    48     while (fgets(msg.mtext+4, MSGMAX, stdin) != NULL)
    49     {
    50         if (msgsnd(msgid, &msg, 4+strlen(msg.mtext+4), 0) < 0)
    51             ERR_EXIT("msgsnd");
    52 
    53         //前四个字节是自己的pid,就不清空了。
    54         memset(msg.mtext+4, 0, MSGMAX-4);
    55         if ((n = msgrcv(msgid, &msg, MSGMAX, pid, 0)) < 0)
    56                         ERR_EXIT("msgsnd");
    57 
    58         fputs(msg.mtext+4, stdout);
    59         memset(msg.mtext+4, 0, MSGMAX-4);
    60     }
    61 }
    62 
    63 int main(int argc, char *argv[])
    64 {
    65     int msgid;
    66     msgid = msgget(0x1234, 0);
    67     if (msgid == -1)
    68         ERR_EXIT("msgget");
    69 
    70     echo_cli(msgid);
    71     return 0;
    72 }

     这个模型下所有进程统一通过队列通信,队列的大小有限制,而且这些进程既从这个队列读又往这个队列写,操作时无序的,很容易造成队列满或者队列空,所以当进程数很多时容易发生阻塞。

    可以改进为如下的模型:

    每来一个客户端,就fork一个进程,让这个进程和客户端通信。

    监控模型:每一个客户端进程是一个监控模块,将监控到的消息统一发给一个总服务进程,然后这个总服务进程开一个端口统一发给外部。这里说的客户端进程和总服务进程是在一个机器上的。

  • 相关阅读:
    【转】Android listview与adapter用法
    【转】 Android Fragment 真正的完全解析(下)
    Jupyter Notebook 基本使用
    斯坦福CS231n学习--初识
    MatConvNet 练习使用CNN
    数据库系统学习(四)- 关系模型之关系代数
    操作系统学习(一)--概述启动过程
    数据库系统学习(三)- 关系模型之基本概念
    数据库系统学习(二)- 基础模型
    数据库系统学习(一)-入门篇
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9426816.html
Copyright © 2020-2023  润新知