今天主要和大家分享有关System V 消息队列一个服务器带多个客户端。客户端把进程ID用作消息类型。每个客户把自己的进程ID指定为msgrcv的type参数,这样服务器就可以很好的进行区分。。。。
其大致的流程如下图:
首先给出客户端的代码:
#include"uitil.h"
int main(int argc,char*argv[])
{
int msqid;
//客户端打开消息队列
msqid = msgget(MQ_KEY1,0);
if(msqid == -1){
cout << "msgget error." << endl;
exit(1);
}
client(msqid,msqid);
return 0;
}
接下来给出服务器端代码:
#include"uitil.h"
int main(int argc,char*argv[])
{
int msqid;
//创建消息队列
msqid = msgget(MQ_KEY1,SVMSG_MODE | IPC_CREAT);
if(msqid == -1){
cout << "msgget error." << endl;
exit(1);
}
server(msqid,msqid);
return 0;
}
头文件uitil.h:
#pragma once
#include<iostream>
#include<sys/msg.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<unistd.h>
#include <fcntl.h>
#include<errno.h>
using namespace std;
#define MQ_KEY1 1234L
#define MQ_KEY2 2345L
#define PIPE_BUFF 4096
#define MAXMESGDATA (PIPE_BUFF - 2 * sizeof(long))
#define MSG_R 0400 //read permission
#define MSG_W 0200 //write permission
#define SVMSG_MODE (MSG_R | MSG_W | MSG_R >> 3 | MSG_R >> 6)
struct mymesg{
long mesg_len;
long mesg_type;
char mesg_data[MAXMESGDATA];
};
ssize_t mesg_send(int id,struct mymesg *mptr)
{
return (msgsnd(id,&(mptr->mesg_type),mptr->mesg_len,0));
}
ssize_t mesg_recv(int id,struct mymesg *mptr)
{
ssize_t n;
n = msgrcv(id,&(mptr->mesg_type),MAXMESGDATA,mptr->mesg_type,0);
mptr->mesg_len = n;
return (n);
}
//客户端函数
void client(int readfd,int writefd)
{
size_t len;
ssize_t n;
char *ptr;
struct mymesg mesg;
//首先在mesg_data中放入进程的id号
snprintf(mesg.mesg_data,MAXMESGDATA,"%ld ",(long)getpid());
len = strlen(mesg.mesg_data);
ptr = mesg.mesg_data + len;
//接着通过fgets函数接收路径名
fgets(ptr,MAXMESGDATA - len,stdin);
len = strlen(mesg.mesg_data);
if(mesg.mesg_data[len - 1] == '\n'){
len--;
}
mesg.mesg_len = len;
mesg.mesg_type = 1;
//将mesg中的内容(id + 空格 + 路径名)写入消息队列MQ_KEY1
mesg_send(writefd,&mesg);
//获取该进程的pid,根据pid类型进行接收
mesg.mesg_type = getpid();
//将接收到的内容显示在屏幕
while((n = mesg_recv(readfd,&mesg)) > 0){
write(STDOUT_FILENO,mesg.mesg_data,n);
}
}
void server(int readfd,int writefd)
{
FILE *fp;
char *ptr;
pid_t pid;
ssize_t n;
struct mymesg mesg;
//该服务器是一个迭代服务器
for(;;){
mesg.mesg_type = 1;
//首先将消息队列MQ_KEY1的内容,读入到mesg中
if((n = mesg_recv(readfd,&mesg)) == 0){
cout << "pathing missing." << endl;
continue;
}
mesg.mesg_data[n] = '\0';
//ptr指向路径名
if((ptr = strchr(mesg.mesg_data,' ')) == NULL){
printf("bogus request: %s\n",mesg.mesg_data);
continue;
}
*ptr++ = 0;
pid = atol(mesg.mesg_data);
mesg.mesg_type = pid;
if((fp = fopen(ptr,"r")) == NULL){
//打开失败时,显示错误
snprintf(mesg.mesg_data + n,sizeof(mesg.mesg_data) - n,
":can't open,%s\n",strerror(errno));
mesg.mesg_len = strlen(ptr);
memmove(mesg.mesg_data,ptr,mesg.mesg_len);
mesg_send(writefd,&mesg);
}else{
//当打开成功时,将文件的内容写入到消息队列
while(fgets(mesg.mesg_data,MAXMESGDATA,fp) != NULL){
mesg.mesg_len = strlen(mesg.mesg_data);
mesg_send(writefd,&mesg);
}
fclose(fp);
}
mesg.mesg_len = 0;
mesg_send(writefd,&mesg);
}
}
我们在后台启动服务器,然后开启两个客户端,其执行结果如下:
文件名为test,其文件的内容通过服务器给出。。。
文件名为test1,其文件的内容也通过服务器给出。。。。