System V消息队列(三)

本文探讨了利用消息队列实现客户/服务器交互的方法,通过类型区分和进程标识实现高效的数据传输和回射。同时指出可能存在的死锁问题,并提供了服务器和客户端的代码实现。

利用消息队列实现回射客户/服务器

队列达到复用的目的

     类型区分: 服务器用1标识类型,客户端用自己的进程 标识类型

    对于服务器端来说,接收到一个消息结构体的类型如果为1,表示是客户请求,而mtex 字段的前4个字节存放着不同进程的pid ,后续字节才是真正的数据,服务器回射客户端时,将pid 作为类型,mtex 为实际数据,客户端只接收对应类型的数据,故可以区分不同客户端


存在缺点:

           可能出现死锁,当服务器正在回射的时候,有客户请求写入数据,队列会出现拥塞.

服务器代码:

#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m) \
		do \
		{ \
			perror(m); \
			exit(EXIT_FAILURE); \
		}while(0)


#define MSGMAX 8192
struct msgbuf {
               long mtype;          // message type, m-+ust be > 0 
               char mtext[MSGMAX];  // message data ,最大消息长度为8192
           };

void echo_ser(int msgid)
{
	struct msgbuf msg;
	bzero(&msg,sizeof(msg));
	int nrcv=0;
	while(1)
	{
		if( (nrcv=msgrcv(msgid,&msg,MSGMAX,1,0)) < 0)  //服务器只接收类型为1消息
			ERR_EXIT("msgrcv err");
		//printf("nrcv=%d\n",nrcv);
		int pid = *((int*)msg.mtext);  // 获取前4个字节,客户端的进程号
		fputs(msg.mtext+4,stdout);  // 打印4字节后的数据部分内容
		msg.mtype = pid;  // 只修改了类型,用进程的进程号填充,注意数据部分没有修改,用来回射
		msgsnd(msgid,&msg,nrcv,0);  //回射的长度为实际接收的长度
		bzero(&msg,sizeof(msg));
	}	
}

int main(int argc,char* argv[])
{	
	int msgid;
	msgid = msgget(1234,IPC_CREAT | 0666);
	if(msgid == -1)
		ERR_EXIT("msgget err");
	echo_ser(msgid);
	return 0;
}


客户端代码:

#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m) \
		do \
		{ \
			perror(m); \
			exit(EXIT_FAILURE); \
		}while(0)


#define MSGMAX 8192
struct msgbuf {
               long mtype;       // message type, must be > 0 
               char mtext[MSGMAX];    // message data 
           };


void echo_cli(int msgid)
{
	int nrcv;
	int pid =getpid();  // 进程统一用4个字节
	struct msgbuf msg;
	bzero(&msg,sizeof(msg));
	
	//msg.mtype =1 ;  // 服务器type默认为1
	*((int*)msg.mtext) = pid;  // 数据部分的前4个字节为进程id,作为客户端的type
	while(fgets(msg.mtext+4,MSGMAX-4,stdin) != NULL)  // 这里的长度应该为4
	{	
		msg.mtype =1;// 发送的时候,这个msg.mtype设置为1,服务器默认的为1
		//printf("%s\n",msg.mtext+4);
		if(msgsnd(msgid,&msg,sizeof(long)+4+strlen(msg.mtext+4),IPC_NOWAIT) < 0)  //发送消息,这里有个问题,为什么多加一次4和少加一次4没有影响
			ERR_EXIT("msgsnd err");
		//printf("%s\n",msg.mtext+4);
		bzero(msg.mtext+4,MSGMAX-4);  // 发送完成后清空
		if((nrcv=msgrcv(msgid,&msg,MSGMAX,pid,0)) <0) // 接收消息
			ERR_EXIT("msgsnd err");
		fputs(msg.mtext +4,stdout);
		bzero(msg.mtext+4,MSGMAX-4);
	}
}

int main(int argc,char* argv[])
{
	int msgid;
	
	msgid = msgget(1234,0);
	if(msgid == -1)
		ERR_EXIT("msgget err");
	
	echo_cli(msgid);
	
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值