模型如下:
服务器:
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一个进程,让这个进程和客户端通信。
监控模型:每一个客户端进程是一个监控模块,将监控到的消息统一发给一个总服务进程,然后这个总服务进程开一个端口统一发给外部。这里说的客户端进程和总服务进程是在一个机器上的。