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一个进程,让这个进程和客户端通信。

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

原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9426816.html