银行模拟系统
- 概述
- 客户端 client.c
- 服务端 serve.c
- 开户 enroll.c
- 存款 save.c
- 转账 transfer.c
- 取款 take.c
- makefile文件
概述
该案例大体过程为,服务器先启动,初始化消息队列和信号,用多线程技术启动开户、存钱、转账、取钱模块,并且可以控制结束。客户端启动后会自动链接服务器,会将用户的请求发送到请求队列,从响应消息队列读取处理结果,并提示给用户。其他模块轮询检测请求消息队列中是否有自己应该去做事情的消息,如果读取到就开始任务,并且将任务结果发送到响应消息队列。
目前用户信息存取是通过txt文件实现的,每个用户单独一个文件。
并且提供了makefile文件生成可执行文件,文件布局如下:
客户端 client.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
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 <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdlib.h>
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 <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
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 <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
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 <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
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 <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
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