1. 上图的一台主机服务器架构的重大缺陷是容易死锁
  2. 因为客户端,服务器都往同一消息队列中发送接收消息,假设消息队列已经满了,此时客户端无法向队列中发送消息,阻塞了,
    而服务器接收完一条消息后,想向消息队列发送消息,由于消息队列已经满了,也阻塞了,此时就会死锁。

  1. 改进型的一台主机服务器架构
  2. 建立两个消息队列,一个用于客户端写入服务器接收,一个用于服务器发送客户端接收,这样则永远不会出现死锁
  1. //本机客户端
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <errno.h>
  7. #include <sys/types.h>
  8. #include <sys/ipc.h>
  9. #include <sys/msg.h>
  10. #include <pthread.h>
  11.  
  12. struct msgbuf
  13. {
  14. long mtype; /* message type, must be > 0 */
  15. char mtext[]; /* message data */
  16. };
  17.  
  18. int get_msqid(const char *pathname)
  19. {
  20. if (pathname == NULL)
  21. {
  22. printf("get_msqid() params not correct !\n");
  23. return -;
  24. }
  25. char *pvalue1 = getenv(pathname);
  26. if (pvalue1 == NULL)
  27. {
  28. printf("getenv() failed !\n");
  29. return -;
  30. }
  31. key_t sendkey = ftok(pvalue1, );
  32. if (sendkey == -)
  33. {
  34. perror("ftok() err");
  35. return -;
  36. }
  37. int msqid = msgget(sendkey, | IPC_CREAT | IPC_EXCL);
  38. if (msqid == -)
  39. {
  40. if (errno == EEXIST)
  41. {
  42. printf("该消息队列已经存在!\n");
  43. msqid = msgget(sendkey, );
  44. } else
  45. {
  46. perror("msgget() err");
  47. return -;
  48. }
  49. }
  50. return msqid;
  51. }
  52.  
  53. void * start_routine(void * arg)
  54. {
  55. //客户端发送消息队列
  56. int msqid = get_msqid("SENDFILE");
  57. struct msgbuf buf;
  58. memset(&buf, , sizeof(buf));
  59. buf.mtype = ;
  60. //数据的前4个字节存放当前进程的pid
  61. *((int *) buf.mtext) = getpid();
  62. while (fgets(buf.mtext + , , stdin) != NULL)
  63. {
  64. //发送消息队列
  65. if (msgsnd(msqid, &buf, sizeof(int) + strlen(buf.mtext + ), ) == -)
  66. {
  67. perror("msgsnd() err");
  68. return NULL;
  69. }
  70. memset(buf.mtext + , , );
  71. }
  72. return NULL;
  73. }
  74.  
  75. int main(int arg, char * args[])
  76. {
  77. //开启多线程
  78. pthread_t thr1;
  79. //设置分离线程
  80. pthread_attr_t attr;
  81. pthread_attr_init(&attr);
  82. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  83. if (pthread_create(&thr1, &attr, start_routine, NULL) != )
  84. {
  85. printf("pthread_create() failed !\n");
  86. return -;
  87. }
  88. //客户端接收消息队列
  89. int msqid = get_msqid("RECVFILE");
  90. //recv
  91. int rc = ;
  92. struct msgbuf buf;
  93. while ()
  94. {
  95. memset(&buf, , sizeof(buf));
  96. rc = msgrcv(msqid, &buf, , getpid(), );
  97. if (rc == -)
  98. {
  99. perror("msgrcv() err");
  100. break;
  101. }
  102. printf("服务器有消息到来,消息长度是%d\n",rc);
  103. fputs(buf.mtext, stdout);
  104. }
  105. return ;
  106. }
  1. //本机服务器
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <errno.h>
  7. #include <sys/types.h>
  8. #include <sys/ipc.h>
  9. #include <sys/msg.h>
  10.  
  11. struct msgbuf
  12. {
  13. long mtype; /* message type, must be > 0 */
  14. char mtext[]; /* message data */
  15. };
  16.  
  17. int get_msqid(const char *pathname)
  18. {
  19. if (pathname == NULL)
  20. {
  21. printf("get_msqid() params not correct !\n");
  22. return -;
  23. }
  24. char *pvalue1 = getenv(pathname);
  25. if (pvalue1 == NULL)
  26. {
  27. printf("getenv() failed !\n");
  28. return -;
  29. }
  30. key_t sendkey = ftok(pvalue1, );
  31. if (sendkey == -)
  32. {
  33. perror("ftok() err");
  34. return -;
  35. }
  36. int msqid = msgget(sendkey, | IPC_CREAT | IPC_EXCL);
  37. if (msqid == -)
  38. {
  39. if (errno == EEXIST)
  40. {
  41. printf("该消息队列已经存在!\n");
  42. msqid = msgget(sendkey, );
  43. } else
  44. {
  45. perror("msgget() err");
  46. return -;
  47. }
  48. }
  49. return msqid;
  50. }
  51.  
  52. int main(int arg, char * args[])
  53. {
  54. /*客户端的发送消息队列,是服务器的接收消息队列*/
  55. int send_msqid = get_msqid("RECVFILE");
  56. if (send_msqid == -)
  57. return -;
  58. int recv_msqid = get_msqid("SENDFILE");
  59. if (recv_msqid == -)
  60. return -;
  61. //接收消息再发送
  62. int rc = ;
  63. struct msgbuf recvbuf;
  64. struct msgbuf sendbuf;
  65. int pid=;
  66. while ()
  67. {
  68. memset(&recvbuf,,sizeof(struct msgbuf));
  69. memset(&sendbuf,,sizeof(struct msgbuf));
  70. rc = msgrcv(recv_msqid, &recvbuf, , , );
  71. if(rc==-)
  72. {
  73. perror("msgrcv() err");
  74. return -;
  75. }
  76. printf("客户端有数据到来!数据的长度是%d\n",rc);
  77. //解析数据
  78. pid=*((int *)recvbuf.mtext);
  79. sendbuf.mtype=pid;
  80. strcpy(sendbuf.mtext,recvbuf.mtext+);
  81. fputs(sendbuf.mtext,stdout);
  82. //发送
  83. if(msgsnd(send_msqid,&sendbuf,rc-,)==-)
  84. {
  85. perror("msgsnd() err");
  86. return -;
  87. }
  88. }
  89. return ;
  90. }
  1. .SUFFIXES:.c .o
  2. CC=gcc
  3. SRCS1=test01.c
  4. OBJS1=$(SRCS1:.c=.o)
  5. EXEC1=clt
  6. SRCS2=tec02.c
  7. OBJS2=$(SRCS2:.c=.o)
  8. EXEC2=ser
  9.  
  10. start:$(OBJS1) $(OBJS2)
  11. $(CC) -o $(EXEC1) $(OBJS1) -lpthread
  12. $(CC) -o $(EXEC2) $(OBJS2)
  13. @echo "-------OK---------"
  14. .c.o:
  15. $(CC) -Wall -g -o $@ -c $<
  16. clean:
  17. rm -f $(OBJS1)
  18. rm -f $(OBJS2)
  19. rm -f $(EXEC1)
  20. rm -f $(EXEC2)

Linux 进程间通讯详解七的更多相关文章

  1. Linux 进程间通讯详解二

    消息队列 --消息队列提供了本机上从一个进程向另外一个进程发送一块数据的方法 --每个数据块都被认为有一个类型,接收者进程接收的数据块可以有不同的类型值 --消息队列也有管道一样的不足,就是每个消息的 ...

  2. Linux 进程间通讯详解一

    进程间的通讯 两台主机间的进程通讯 --socket 一台主机间的进程通讯 --管道(匿名管道,有名管道) --System V进程间通信(IPC)包括System V消息队列,System V信号量 ...

  3. Linux 进程间通讯详解六

    ftok()函数 key_t ftok(const char *pathname, int proj_id); --功能:创建系统建立IPC通讯 (消息队列.信号量和共享内存) 时key值 --参数 ...

  4. Linux 进程间通讯详解三

    msgctl()函数 int msgctl(int msqid, int cmd, struct msqid_ds *buf); --参数 msqid:有msgget函数返回的消息队列标识码 cmd: ...

  5. Linux 进程间通讯详解五

    msgrcv函数 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg); --功能:是从一个消息队列接 ...

  6. Linux 进程间通讯详解四

    msgsnd函数 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); --功能:把一条消息添加到消息队列中 --参数 ...

  7. Linux 进程间通讯方式 pipe()函数 (转载)

    转自:http://blog.csdn.net/ta893115871/article/details/7478779 Linux 进程间通讯方式有以下几种: 1->管道(pipe)和有名管道( ...

  8. Linux 进程间通讯

    一.Linux 下进程间通讯方式 1)管道(Pipe)及有名管道(named pipe): 管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允 ...

  9. [转] linux系统文件流、文件描述符与进程间关系详解

    http://blog.sina.com.cn/s/blog_67b74aea01018ycx.html linux(unix)进程与文件的关系错综复杂,本教程试图详细的阐述这个问题. 包括:     ...

随机推荐

  1. 解决WIN7与虚拟机CentOS的文件夹共享问题

    一.系统与软件 WIN7 64bit.VirtualBox 5.0.14.CentOS 6.5.SecureCRT 7.2.3 二.使用文件夹共享需要安装增强功能,但是安装时无法读取光盘iso文件 三 ...

  2. 关于Lind.DDD.Api客户端的使用与知识分享

    回到目录 关于Lind.DDD.Api的使用与客户端的调用 作者:张占岭 花名:仓储大叔 框架:Lind.DDD,Lind.DDD.Api 目录 Api里注册全局校验特性 1 Api中设置全局的Cor ...

  3. Oracle常用SQL查询(2)

    三.查看数据库的SQL 1 .查看表空间的名称及大小 select  t.tablespace_name,  round ( sum (bytes / ( 1024 * 1024 )), 0 ) ts ...

  4. jQuery动画特效实例教程

    本文以实例形式详细讲述了jQuery动画特效的实现方法. 1.自制折叠内容块 内容块如下:     <div class="module">   <div cla ...

  5. O365(世纪互联)SharePoint 之文档库使用小记

    前言 当O365越来越流行的时候,大家往往更多使用的是传统的Office功能,有太少订阅用户能触及到O365的一个非常棒的功能,叫做SharePoint online. 下面,我们就以图文并茂的方式, ...

  6. 项目实战工具类(一):PhoneUtil(手机信息相关)

    可以使用的功能: 1.获取手机系统版本号 2.获取手机型号 3.获取手机宽度 4.获取手机高度 5.获取手机imei串号 ,GSM手机的 IMEI 和 CDMA手机的 MEID. 6.获取手机sim卡 ...

  7. android VelocityTracker 速度追踪器的使用及创建

    VelocityTracker 速度追踪 第一,创建方式: VelocityTracker  mVelocityTracker  = new VelocityTracker .obtain() 第二, ...

  8. IOS开发基础知识--碎片14

    1:ZIP文件压缩跟解压,使用ZipArchive 创建/添加一个zip包 ZipArchive* zipFile = [[ZipArchive alloc] init]; //次数得zipfilen ...

  9. 原生js实现Ajax

    一般来说,大家可能都会习惯用JQuery提供的Ajax方法,但是用原生的js怎么去实现Ajax方法呢? JQuery提供的Ajax方法: $.ajax({ url: , type: '', dataT ...

  10. Scrum vs. PMP vs. PRINCE2的发展趋势图

    这时2013年来自Google Trends的两幅图,数据来自对“Jobs and Education”的统计,体现了这三种认证,或者视为三种项目实施方式的趋势. 下图是全球的趋势: 下图是美国的趋势 ...