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

改进型的一台主机服务器架构
建立两个消息队列,一个用于客户端写入服务器接收,一个用于服务器发送客户端接收,这样则永远不会出现死锁
//本机客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <pthread.h> struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[]; /* message data */
}; int get_msqid(const char *pathname)
{
if (pathname == NULL)
{
printf("get_msqid() params not correct !\n");
return -;
}
char *pvalue1 = getenv(pathname);
if (pvalue1 == NULL)
{
printf("getenv() failed !\n");
return -;
}
key_t sendkey = ftok(pvalue1, );
if (sendkey == -)
{
perror("ftok() err");
return -;
}
int msqid = msgget(sendkey, | IPC_CREAT | IPC_EXCL);
if (msqid == -)
{
if (errno == EEXIST)
{
printf("该消息队列已经存在!\n");
msqid = msgget(sendkey, );
} else
{
perror("msgget() err");
return -;
}
}
return msqid;
} void * start_routine(void * arg)
{
//客户端发送消息队列
int msqid = get_msqid("SENDFILE");
struct msgbuf buf;
memset(&buf, , sizeof(buf));
buf.mtype = ;
//数据的前4个字节存放当前进程的pid
*((int *) buf.mtext) = getpid();
while (fgets(buf.mtext + , , stdin) != NULL)
{
//发送消息队列
if (msgsnd(msqid, &buf, sizeof(int) + strlen(buf.mtext + ), ) == -)
{
perror("msgsnd() err");
return NULL;
}
memset(buf.mtext + , , );
}
return NULL;
} int main(int arg, char * args[])
{
//开启多线程
pthread_t thr1;
//设置分离线程
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (pthread_create(&thr1, &attr, start_routine, NULL) != )
{
printf("pthread_create() failed !\n");
return -;
}
//客户端接收消息队列
int msqid = get_msqid("RECVFILE");
//recv
int rc = ;
struct msgbuf buf;
while ()
{
memset(&buf, , sizeof(buf));
rc = msgrcv(msqid, &buf, , getpid(), );
if (rc == -)
{
perror("msgrcv() err");
break;
}
printf("服务器有消息到来,消息长度是%d\n",rc);
fputs(buf.mtext, stdout);
}
return ;
}
//本机服务器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[]; /* message data */
}; int get_msqid(const char *pathname)
{
if (pathname == NULL)
{
printf("get_msqid() params not correct !\n");
return -;
}
char *pvalue1 = getenv(pathname);
if (pvalue1 == NULL)
{
printf("getenv() failed !\n");
return -;
}
key_t sendkey = ftok(pvalue1, );
if (sendkey == -)
{
perror("ftok() err");
return -;
}
int msqid = msgget(sendkey, | IPC_CREAT | IPC_EXCL);
if (msqid == -)
{
if (errno == EEXIST)
{
printf("该消息队列已经存在!\n");
msqid = msgget(sendkey, );
} else
{
perror("msgget() err");
return -;
}
}
return msqid;
} int main(int arg, char * args[])
{
/*客户端的发送消息队列,是服务器的接收消息队列*/
int send_msqid = get_msqid("RECVFILE");
if (send_msqid == -)
return -;
int recv_msqid = get_msqid("SENDFILE");
if (recv_msqid == -)
return -;
//接收消息再发送
int rc = ;
struct msgbuf recvbuf;
struct msgbuf sendbuf;
int pid=;
while ()
{
memset(&recvbuf,,sizeof(struct msgbuf));
memset(&sendbuf,,sizeof(struct msgbuf));
rc = msgrcv(recv_msqid, &recvbuf, , , );
if(rc==-)
{
perror("msgrcv() err");
return -;
}
printf("客户端有数据到来!数据的长度是%d\n",rc);
//解析数据
pid=*((int *)recvbuf.mtext);
sendbuf.mtype=pid;
strcpy(sendbuf.mtext,recvbuf.mtext+);
fputs(sendbuf.mtext,stdout);
//发送
if(msgsnd(send_msqid,&sendbuf,rc-,)==-)
{
perror("msgsnd() err");
return -;
}
}
return ;
}
.SUFFIXES:.c .o
CC=gcc
SRCS1=test01.c
OBJS1=$(SRCS1:.c=.o)
EXEC1=clt
SRCS2=tec02.c
OBJS2=$(SRCS2:.c=.o)
EXEC2=ser start:$(OBJS1) $(OBJS2)
$(CC) -o $(EXEC1) $(OBJS1) -lpthread
$(CC) -o $(EXEC2) $(OBJS2)
@echo "-------OK---------"
.c.o:
$(CC) -Wall -g -o $@ -c $<
clean:
rm -f $(OBJS1)
rm -f $(OBJS2)
rm -f $(EXEC1)
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. R语言数据处理包dplyr、tidyr笔记

    dplyr包是Hadley Wickham的新作,主要用于数据清洗和整理,该包专注dataframe数据格式,从而大幅提高了数据处理速度,并且提供了与其它数据库的接口:tidyr包的作者是Hadley ...

  2. wParam和lParam两个参数到底是什么意思?

    在Windows的消息函数中,有两个非常熟悉的参数:wParam,lParam. 这两个参数的字面意义对于现在的程序来说已经不重要了,因为它是16位系统的产物,为了保持程序的可移植性,就将它保存了下来 ...

  3. Linux(Centos)之安装Nginx及注意事项

    1.Nginx的简单说明 a.  Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器,期初开发的目的就是为了代理电子邮件服务器室友:Igor Sysoev开发 ...

  4. 破壳漏洞利用payload—shellshock in the wild

    FireEye关于破壳漏洞(shellshock)在现实中的利用有一篇文章: shellshock in the wild 原文较长,进行了对CGI利用的详细分析,笔者比较感兴趣的是Shellshoc ...

  5. 免费薪资总额管控系统-JXHR2016

    •工资总额是指按照国家统计局规定的统计口径或企业规定,在一定时期内支付给各类用工的劳动报酬总额 •工资总额,即基本工资,包括岗位工资.各项津补贴 •JXHR2016以薪酬管控为核心,结合人力资源规划. ...

  6. collection view 开发笔记

    使用collectionView 注册的cell 不会调用 init 方法 会调用 initwith fram 方法.

  7. 在eclipse中把Tomcat 8删掉不能重建问题,启动Tomcat重置本地配置问题

    转载:http://blog.csdn.net/caiwenfeng_for_23/article/details/45480039 PS: 今天手贱,把Eclipse里的tomcat删掉了,然后发现 ...

  8. Servlet的生命周期+实现方式

    1.Servlet的生命周期:        (1)被创建:            默认情况下,Servlet第一次被访问时,被服务器创建.会调用init()方法.                一个 ...

  9. initialize和init以及load方法的区别与使用以及什么时候调用

    initialize不是init initialize在这个类第一次被调用的时候比如[[class alloc]init]会调用一次initialize方法,不管创建多少次这个类,都只会调用一次这个方 ...

  10. 12-返回指针的函数&&指向函数的指针

    前言 接下来我只讲指针的最常见用法,比如这一章的内容----返回指针的函数 与 指向函数的指针   一.返回指针的函数 指针也是C语言中的一种数据类型,因此一个函数的返回值肯定可以是指针类型的. 返回 ...