利用消息队列实现回射客户/服务器
队列达到复用的目的
类型区分: 服务器用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;
}