基于消息队列+多进程编写的银行模拟系统

银行模拟系统

  • 概述
  • 客户端 client.c
  • 服务端 serve.c
  • 开户 enroll.c
  • 存款 save.c
  • 转账 transfer.c
  • 取款 take.c
  • makefile文件

概述

  该案例大体过程为,服务器先启动,初始化消息队列和信号,用多线程技术启动开户、存钱、转账、取钱模块,并且可以控制结束。客户端启动后会自动链接服务器,会将用户的请求发送到请求队列,从响应消息队列读取处理结果,并提示给用户。其他模块轮询检测请求消息队列中是否有自己应该去做事情的消息,如果读取到就开始任务,并且将任务结果发送到响应消息队列。
  目前用户信息存取是通过txt文件实现的,每个用户单独一个文件。
  并且提供了makefile文件生成可执行文件,文件布局如下:

基于消息队列+多进程编写的银行模拟系统_第1张图片

客户端 client.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int reqid;//请求队列id
int resid;//响应队列id

typedef struct msgbuff
{
   long mtype;
   char name[20];
   char password[20];
   float money;
}user;

typedef struct resbuff
{
   long type;
   char name[20];
   char msg[256];
   float money;
}res;

void menu(void);				//菜单
void enroll(void);				//开户
void save_money(void);			//存钱
void transfer_money(void);		//转账
void take_money(void);			//取钱

int main(int argc,char *argv[])
{
   while(1)
   {
   	menu();
   }
}


void menu(void)
{
   system("clear");
   printf("\n\t欢迎使用wwz银行ATM机\n");
   printf("\t\t1:开户\n");
   printf("\t\t2:存钱\n");
   printf("\t\t3:转账\n");
   printf("\t\t4:取钱\n");
   printf("\t请输入1-4进行选择:\n");
   int key;
   scanf("%d",&key);
   switch(key)
   {
   	case 1 :	enroll();			break;
   	case 2 :	save_money();		break;
   	case 3 :	transfer_money();	break;
   	case 4 :	take_money();		break;
   default:printf("输入有误请重新输入\n");sleep(1);break;
   }
}
void enroll(void)
{
   system("clear");
   //键值
   key_t key1 = ftok("/home/wwz/xyd/bank/out",1);
   key_t key2 = ftok("/home/wwz/xyd/bank/out",2);
   //打开请求消息队列
   reqid = msgget(key1,IPC_CREAT|0644);
   if(reqid== -1){perror("msgget");return;}
   //打开应答消息队列
   resid =msgget(key2,IPC_CREAT|0644);
   if(resid == -1){perror("msgget");return;}
   //读取信息
   printf("请输入用户名、密码、存钱金额\n");
   user u;
   scanf("%s %s %f",u.name,u.password,&u.money);
   //发送到请求队列
   u.mtype = 1;
   msgsnd(reqid,&u,sizeof(user)-sizeof(long),0);
   //接收请求结果
   res r;
   msgrcv(resid,&r,sizeof(res),1,0);  //1对应上面的1
   printf("%s",r.msg);
   return;
}
void save_money(void)
{
   system("clear");
   //键值
   key_t key1 = ftok("/home/wwz/xyd/bank/out",1);
   key_t key2 = ftok("/home/wwz/xyd/bank/out",2);
   //打开请求消息队列
   reqid = msgget(key1,IPC_CREAT|0644);
   if(reqid== -1){perror("msgget");return;}
   //打开应答消息队列
   resid =msgget(key2,IPC_CREAT|0644);
   if(resid == -1){perror("msgget");return;}
   //读取信息
   printf("请输入用户名、密码、存钱金额\n");
   user u;
   scanf("%s %s %f",u.name,u.password,&u.money);
   //发送到请求队列
   u.mtype = 2;
   msgsnd(reqid,&u,sizeof(user)-sizeof(long),0);
   //接收请求结果
   res r;
   msgrcv(resid,&r,sizeof(res),2,0);  //1对应上面的1
   printf("%s",r.msg);
   return;
}
void transfer_money(void)
{
   system("clear");
   //键值
   key_t key1 = ftok("/home/wwz/xyd/bank/out",1);
   key_t key2 = ftok("/home/wwz/xyd/bank/out",2);
   //打开请求消息队列
   reqid = msgget(key1,IPC_CREAT|0644);
   if(reqid== -1){perror("msgget");return;}
   //打开应答消息队列
   resid =msgget(key2,IPC_CREAT|0644);
   if(resid == -1){perror("msgget");return;}
   //读取信息
   printf("请输入用户名、密码、转账金额、转账账户\n");
   user u1,u2;
   scanf("%s %s %f %s",u1.name,u1.password,&u1.money,u2.name);
   //发送到请求队列
   u1.mtype = 4;
   u2.mtype = 5;
   msgsnd(reqid,&u1,sizeof(user)-sizeof(long),0);
   msgsnd(reqid,&u2,sizeof(user)-sizeof(long),0);
   //接收请求结果
   res r1,r2;
   msgrcv(resid,&r1,sizeof(res),4,0);
   msgrcv(resid,&r2,sizeof(res),5,0);
   printf("%s\t",r1.msg);
   printf("%s",r2.msg);
   return;
}
void take_money(void)
{
   system("clear");
   //键值
   key_t key1 = ftok("/home/wwz/xyd/bank/out",1);
   key_t key2 = ftok("/home/wwz/xyd/bank/out",2);
   //打开请求消息队列
   reqid = msgget(key1,IPC_CREAT|0644);
   if(reqid== -1){perror("msgget");return;}
   //打开应答消息队列
   resid =msgget(key2,IPC_CREAT|0644);
   if(resid == -1){perror("msgget");return;}
   //读取信息
   printf("请输入用户名、密码、取钱金额\n");
   user u;
   scanf("%s %s %f",u.name,u.password,&u.money);
   //发送到请求队列
   u.mtype = 3;
   msgsnd(reqid,&u,sizeof(user)-sizeof(long),0);
   //接收请求结果
   res r;
   msgrcv(resid,&r,sizeof(res),3,0);  //1对应上面的1
   printf("%s",r.msg);
   return;
}

服务端 serve.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static int reqid = -1; //作为请求的消息队列的返回id
static int resid = -1;  //作为响应的消息队列的返回id

typedef struct Service{
    char path[256];
    pid_t pid;
}Srv;
static Srv srv[]={ 
    {"./out/enroll",-1},      	//开户
    {"./out/save",-1},      	//存款
    {"./out/take",-1},  		//取款
    {"./out/trans",-1},     	//转账
};

int Init_msg();				//初始化消息队列
void deInit_msg();			//销毁消息队列
void sigint(int signum);	//初始化信号
int start();				//启动服务器
int stop();					//关闭服务器

int main(int argc,char *argv[])
{
	atexit(deInit_msg);
	signal(SIGINT,sigint);
	if(Init_msg() == -1){return -1;}
    if(start() == -1){return -1;}
    sleep(1);
    //阻塞等待退出
    printf("按<回车>键退出......\n");
    getchar();
    if(stop() == -1){return -1;}
    return 0;
}
int Init_msg()
{
    printf("服务器初始化.....\n");
    
    //键值
	key_t key1 = ftok("/home/wwz/xyd/bank/out",1);
	key_t key2 = ftok("/home/wwz/xyd/bank/out",2);
	//创建
    reqid = msgget(key1,IPC_CREAT|0644);
	if(reqid == -1){perror("msgget");return -1;}
    printf("创建请求消息队列成功!\n");
    resid = msgget(key2,IPC_CREAT|0644);
	if(resid == -1){perror("msgget");return -1;}
    printf("创建应答消息队列成功!\n");
    return 0;
}
void deInit_msg()
{
    printf("服务器关闭.....\n");
    if(msgctl(reqid,IPC_RMID,NULL) == -1){perror("msgctl");}
    else	printf("销毁请求消息队列成功!\n");
    if(msgctl(resid,IPC_RMID,NULL) == -1)perror("msgctl");
    else	printf("销毁应答消息队列成功!\n");
}
void sigint(int signum)
{
    printf("%d\n",signum);
    stop();
    exit(0);
}

int start()
{
    printf("启动服务器\\n");
    size_t i;
    for(i=0; i<sizeof(srv)/sizeof(srv[0]); i++)
    {
        if((srv[i].pid = vfork()) == -1)
        {perror("vfork");return -1;}
        if(srv[i].pid == 0)
        {
            if(execl(srv[i].path,srv[i].path,NULL)==-1)
            {
                perror("execl");
                return -1;
            }
            return 0;
        }
    }
    return 0;
}
int stop()
{
    printf("关闭服务器\n");
    size_t i;
    for(i=0; i<sizeof(srv)/sizeof(srv[0]); i++)
    {
        if(kill(srv[i].pid,SIGINT) == -1)
        {
            perror("kill");
            return -1;
        }
    }
    for(;;)if(wait(NULL) == -1){perror("wait");break;}
    return 0;
}

开户 enroll.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int reqid; 
int resid; 

typedef struct msgbuff
{
	long mtype;
	char name[20];
	char password[20];
	float money;
}user;

typedef struct resbuff
{
	long type;
	char name[20];
	char msg[256];
	float money;
}res;
//停止服务函数
void stop_fun(void)
{
	printf("开户服务停止\n");
	exit(0);
}
//保存信息函数
int save(const user *u)
{
	char pathname[256] = {0};
	sprintf(pathname,"/home/wwz/xyd/bank/data/%s.txt",u->name);
	FILE * fp = fopen(pathname,"w+");
	if(fp == NULL){perror("save:fopen");return -1;}
	fprintf(fp,"%s\t%s\t%lf\n",u->name,u->password,u->money);
	fclose(fp);
	return 0;
}

int main(int argc,char *argv[])
{
	signal(SIGINT,(void *)stop_fun);
	//键值
	key_t key1 = ftok("/home/wwz/xyd/bank/out",1);
	key_t key2 = ftok("/home/wwz/xyd/bank/out",2);
	//打开请求消息队列
	reqid = msgget(key1,IPC_CREAT|0644);
	if(reqid == -1){perror("msgget");return -1;}
	//打开应答消息队列
	resid = msgget(key2,IPC_CREAT|0644);
	if(resid == -1){perror("msgget");return -1;}
	
	printf("开户服务启动\n");
	while(1)
	{
		//轮循等待从队列中读出数据
		user req;
		if(msgrcv(reqid,&req,sizeof(req)-sizeof(long),1,0)==-1)
		{perror ("msgrcv");continue;}
		
		printf("开户帐号:");
        printf("%s\n",req.name);
		
		res r;
		strcpy(r.name,req.name);
		//打开文件并且确认是否有该用户
		char temp[128]={0};
		sprintf(temp,"/home/wwz/xyd/bank/data/%s.txt",req.name);
		//只写,如果打不开就证明没有,能打开就是有了
		int fp = open(temp,O_WRONLY);
		
		if(fp>0)
		{
			r.type = 1;
			sprintf(r.msg,"已有该用户,开户失败!");
			msgsnd(resid,&r,sizeof(res)-sizeof(long),0);
		}
		else
		{
			save(&req);
			sprintf(r.msg,"开户成功!");
			msgsnd(resid,&r,sizeof(res)-sizeof(long),0);
		}
		close(fp);
	}
	return 0;
}

存款 save.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int reqid; 
int resid; 

typedef struct msgbuff
{
	long mtype;
	char name[20];
	char password[20];
	float money;
}user;

typedef struct resbuff
{
	long type;
	char name[20];
	char msg[256];
	float money;
}res;

void * stop_fun(void)
{
	printf("存款服务停止\n");
	exit(0);
}

int get(char name[20],user *u)
{
	char pathname[256] = {0};
	sprintf(pathname,"/home/wwz/xyd/bank/data/%s.txt",name);
	FILE * fp = fopen(pathname,"r");
	if(fp == NULL){perror("get:fopen");return -1;}
	fscanf(fp,"%s\t%s\t%f\n",u->name,u->password,&u->money);
	fclose(fp);
	return 1;
}

int save(const user *u)
{
	char pathname[256] = {0};
	sprintf(pathname,"/home/wwz/xyd/bank/data/%s.txt",u->name);
	FILE * fp = fopen(pathname,"w+");
	if(fp == NULL){perror("save:fopen");return -1;}
	fprintf(fp,"%s\t%s\t%lf\n",u->name,u->password,u->money);
	fclose(fp);
	return 0;
}

int main(int argc,char *argv[])
{
	signal(SIGINT,(void *)stop_fun);
	//键值
	key_t key1 = ftok("/home/wwz/xyd/bank/out",1);
	key_t key2 = ftok("/home/wwz/xyd/bank/out",2);
	//打开请求消息队列
	reqid = msgget(key1,IPC_CREAT|0644);
	if(reqid == -1){perror("msgget");return -1;}
	//打开应答消息队列
	resid = msgget(key2,IPC_CREAT|0644);
	if(resid == -1){perror("msgget");return -1;}
	
	printf("存款服务启动\n");
	while(1)
	{
		//轮循等待从队列中读出数据
		user req;
		if(msgrcv(reqid,&req,sizeof(req)-sizeof(long),2,0)==-1)
		{perror ("msgrcv");continue;}
        printf("存款帐号:%s\n",req.name);
		res r;
		user u;
		if(get(req.name,&u)==-1)
		{sprintf(r.msg,"无效账户");goto send;}
		
		if(strcmp(req.password,u.password)!=0)
		{sprintf(r.msg,"密码错误");goto send;}
		
		u.money += req.money;
		if(save(&u) == -1)
		{sprintf(r.msg,"存款失败");goto send;}
		r.money = u.money;
		sprintf(r.msg,"存款成功");
send:		
		r.type = 2;
		if(msgsnd(resid,&r,sizeof(res)-sizeof(long),0)==-1)
        {perror("msgsnd");continue;}
	}
	return 0;
}

转账 transfer.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int reqid; 
int resid; 

typedef struct msgbuff
{
	long mtype;
	char name[20];
	char password[20];
	float money;
}user;

typedef struct resbuff
{
	long type;
	char name[20];
	char msg[256];
	float money;
}res;

void  stop_fun(void)
{
	printf("转账服务停止\n");
	exit(0);
}

int get(char name[20],user *u)
{
	char pathname[256] = {0};
	sprintf(pathname,"/home/wwz/xyd/bank/data/%s.txt",name);
	FILE * fp = fopen(pathname,"r");
	if(fp == NULL){perror("get:fopen");return -1;}
	fscanf(fp,"%s\t%s\t%f\n",u->name,u->password,&u->money);
	fclose(fp);
	return 1;
}

int save(const user *u)
{
	char pathname[256] = {0};
	sprintf(pathname,"/home/wwz/xyd/bank/data/%s.txt",u->name);
	FILE * fp = fopen(pathname,"w+");
	if(fp == NULL){perror("save:fopen");return -1;}
	fprintf(fp,"%s\t%s\t%lf\n",u->name,u->password,u->money);
	fclose(fp);
	return 0;
}

int main(int argc,char *argv[])
{
	
	signal(SIGINT,(void *)stop_fun);
	//键值
	key_t key1 = ftok("/home/wwz/xyd/bank/out/",1);
	key_t key2 = ftok("/home/wwz/xyd/bank/out/",2);
	//打开请求消息队列
	reqid = msgget(key1,IPC_CREAT|0644);
	if(reqid == -1){perror("msgget");return -1;}
	//打开应答消息队列
	resid = msgget(key2,IPC_CREAT|0644);
	if(resid == -1){perror("msgget");return -1;}
	
	while(1)
	{
		//轮循等待从队列中读出数据
		user req1,req2;
		if(msgrcv(reqid,&req1,sizeof(user)-sizeof(long),4,0)==-1)
		{perror ("req1:msgrcv");continue;}
		if(msgrcv(reqid,&req2,sizeof(user)-sizeof(long),5,0)==-1)
		{perror ("req2:msgrcv");continue;}
		
		res r1,r2;
		user u1,u2;
		
		memset(r1.msg,0,sizeof(r1.msg));
		memset(r2.msg,0,sizeof(r2.msg));
		
		printf("转账帐号:%s  收款帐号:%s\n",req1.name,req2.name);
		
		if(get(req1.name,&u1)==-1)
		{strcpy(r1.msg,"转账账户为无效账户");goto send;}
		if(get(req2.name,&u2)==-1)
		{strcpy(r2.msg,"收款账户为无效账户");goto send;}
		if(strcmp(req1.password,u1.password))
		{strcpy(r1.msg,"密码错误");goto send;}
		if(req1.money>u1.money)
		{sprintf(r1.msg,"抱歉,余额不足,您的余额为:%f",u1.money);goto send;}
		u1.money -= req1.money;
		u2.money += req1.money;
		if(save(&u1) == -1)
		{strcpy(r1.msg,"转账失败");goto send;}
		if(save(&u2) == -1)
		{strcpy(r2.msg,"收款失败");goto send;}
		
		r1.money = u1.money;
		r2.money = u2.money;
		
		sprintf(r1.msg,"转账成功,您的余额为:%f",u1.money);
		strcpy(r2.msg,"收款成功");
send:		
		r1.type = 4;
		if(msgsnd(resid,&r1,sizeof(res)-sizeof(long),0)==-1)
        {perror("msgsnd");continue;}
send2:
		r2.type = 5;
		if(msgsnd(resid,&r2,sizeof(res)-sizeof(long),0)==-1)
        {perror("msgsnd");continue;}
	}
	return 0;
}

取款 take.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int reqid; 
int resid; 

typedef struct msgbuff
{
	long mtype;
	char name[20];
	char password[20];
	float money;
}user;

typedef struct resbuff
{
	long type;
	char name[20];
	char msg[256];
	float money;
}res;

void  stop_fun(void)
{
	printf("取款服务停止\n");
	exit(0);
}

int get(char name[20],user *u)
{
	char pathname[256] = {0};
	sprintf(pathname,"/home/wwz/xyd/bank/data/%s.txt",name);
	FILE * fp = fopen(pathname,"r");
	if(fp == NULL){perror("get:fopen");return -1;}
	fscanf(fp,"%s\t%s\t%f\n",u->name,u->password,&u->money);
	fclose(fp);
	return 1;
}

int save(const user *u)
{
	char pathname[256] = {0};
	sprintf(pathname,"/home/wwz/xyd/bank/data/%s.txt",u->name);
	FILE * fp = fopen(pathname,"w+");
	if(fp == NULL){perror("save:fopen");return -1;}
	fprintf(fp,"%s\t%s\t%lf\n",u->name,u->password,u->money);
	fclose(fp);
	return 0;
}

int main(int argc,char *argv[])
{
	signal(SIGINT,(void *)stop_fun);
	//键值
	key_t key1 = ftok("/home/wwz/xyd/bank/out/",1);
	key_t key2 = ftok("/home/wwz/xyd/bank/out/",2);
	//打开请求消息队列
	reqid = msgget(key1,IPC_CREAT|0644);
	if(reqid == -1){perror("msgget");return -1;}
	//打开应答消息队列
	resid = msgget(key2,IPC_CREAT|0644);
	if(resid == -1){perror("msgget");return -1;}
	
	printf("取款服务启动\n");
	while(1)
	{
		//轮循等待从队列中读出数据
		user req;
		if(msgrcv(reqid,&req,sizeof(req)-sizeof(long),3,0)==-1)
		{perror ("msgrcv");continue;}
		printf("取款帐号:%s\n",req.name);
		res r;
		user u;
		if(get(req.name,&u)==-1)
		{strcpy(r.msg,"无效账户");goto send;}
		if(strcmp(req.password,u.password))
		{strcpy(r.msg,"密码错误");goto send;}
		if(req.money>u.money)
		{sprintf(r.msg,"抱歉,余额不足,您的余额为:%f",u.money);goto send;}
		u.money -= req.money;
		if(save(&u) == -1)
		{strcpy(r.msg,"取款失败");goto send;}
		r.money = u.money;
		sprintf(r.msg,"取款成功,您的余额为:%f",u.money);
send:		
		r.type = 3;
		if(msgsnd(resid,&r,sizeof(res)-sizeof(long),0)==-1)
        {perror("msgsnd");continue;}
	}
	return 0;
}

makefile文件

all:serve client ./out/enroll ./out/save ./out/take ./out/trans
obj = $(wildcard ./src/*.c)

serve:$(obj)
	gcc  ./src/serve.c -o $@
client:$(obj)
	gcc  ./src/client.c -o $@
./out/enroll:$(obj)
	gcc  ./src/enroll.c -o $@
./out/save:$(obj)
	gcc ./src/save.c -o $@
./out/take:$(obj)
	gcc  ./src/take.c -o $@
./out/trans:$(obj)
	gcc  ./src/transfer.c -o $@

clean:
	rm serve client ./out/enroll ./out/save ./out/take ./out/trans
.PHONY:clean

你可能感兴趣的:(linux,MakeFile,linux,c语言,消息队列,多线程)