这是一个基于信息队列的银行管理系统客户端的项目代码详细讲解,主要介绍了开户、存款、取款等等任务在客户端的运行,代码比较简单,但是每一段代码都进行了详细的讲解,源代码主要来源于:
Linux系统编程阶段项目:基于消息队列的银行管理系统
本文基于其代码进行详细的讲解,也是我拜读其博客之后详细研究后的记录。
头文件及结构体
#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>
int g_reqid; //作为请求的消息队列的返回id
int g_resid; //作为应答消息队列的返回id
typedef struct msgbuf{
long mtype; //消息类型
char id[100]; //账户
char name[256]; //用户名
char pw[9]; //密码
float money; //银行卡余额
}userm;
typedef struct tag_OpenRespond{
long type;
char id[100]; //账户
char msg[256];
float money; //银行卡余额
}RES; //让客户端从应答消息队列读到的反馈存到这里
主函数
int main()
{
while(1)
{
menu();
int a;
printf("请输入要执行的操作!\n");
scanf("%d",&a);
switch(a)
{
case 1:Account();break;//开户
case 2:Deposit();break;//存款
case 3:withdrawal();break;//取款
case 4:Inquire();break;//查询
case 5:Transfer();break;//转账
case 6:Logout();break;//注销
case 7:
return 0;
}
}
}
主函数非常简单:
- 主要就是一个循环体
while(1)
; - 接着输出一个目录
menu()
; - 用户输入一个数值选择要操作的函数;对应的是下面的
switch
选择语句; - 用户输入1的话就是开户,对应的函数为
Account()
; - 用户输入2的话就是存款,对应的函数为
Deposit()
; - 用户输入3的话就是取款,对应的函数为
Withdrawal()
; - 用户输入4的话就是查询,对应的函数为
Inquire()
; - 用户输入5的话就是转账,对应的函数为
Transfer()
; - 用户输入6的话就是注销,对应的函数为
Logout()
; - 用户输入7的话就是退出。
接下来就是一步步解决这些函数的问题:
菜单
void menu()
{
printf("*********欢迎来到小黑银行!************\n");
printf("**************1.开户******************\n");
printf("**************2.存款******************\n");
printf("**************3.取款******************\n");
printf("**************4.查询******************\n");
printf("**************5.转账******************\n");
printf("**************6.销户******************\n");
printf("**************7.退出******************\n");
}
实现菜单功能非常简单,只需要标准输出就行,不需要考虑端口问题,端口让下面的函数实现。
一、开户
void Account()
{
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;//错误提示
}
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
userm a;
printf("请输入要注册的身份号!\n");
scanf("%s",a.id);
printf("请输入要注册的用户名!\n");
scanf("%s",a.name);
printf("请输入要注册的密码!\n");
scanf("%s",a.pw);
printf("请输入要注册的余额!\n");
scanf("%f",&a.money);
//往请求消息队列写
a.mtype = 1; //消息类型为1,开户用
msgsnd(g_reqid,&a,sizeof(userm)-sizeof(long),0);
//读应答消息队列
RES buf;
msgrcv(g_resid,&buf,sizeof(buf),1,0); //1类消息,开户用
printf("%s\n",buf.msg);
return;
}
代码解释
这段代码是一个C语言函数,用于打开两个消息队列并向其中写入和读取消息。
首先,使用ftok
函数生成两个键值,这些键值用于唯一标识消息队列。ftok
函数需要传入一个文件路径和一个整数值,它会根据这些参数生成一个唯一的键值。
然后,使用msgget
函数打开请求消息队列和应答消息队列。msgget
函数接受两个参数,一个是键值,另一个是标志位。IPC_CREAT
表示如果消息队列不存在则创建一个新的,0644
表示设置权限为读写。
接下来,定义了一个名为userm
的结构体变量a
,用于存储用户的注册信息。然后通过printf
和scanf
函数分别提示用户输入身份号、用户名、密码和余额,并将用户输入的值存储到结构体变量a
的相应字段中。
之后,设置了a
的mtype
字段为1,表示这条消息是用于开户的。然后使用msgsnd
函数将结构体变量a
写入请求消息队列。msgsnd
函数接受五个参数,分别是消息队列的ID、指向消息的指针、消息的大小、消息的类型和标志位。这里的消息类型是1,表示开户用。
最后,使用msgrcv
函数从应答消息队列中读取消息。msgrcv
函数接受五个参数,分别是消息队列的ID、指向消息的指针、消息的大小、消息的类型和标志位。这里的消息类型是1,表示开户用。读取到的消息存储在名为buf
的结构体变量中。然后使用printf
函数打印出消息的内容。
整个函数的目的是向请求消息队列写入用户的注册信息,并从应答消息队列中读取开户结果并打印出来。
二、存款
void Deposit()//存款业务
{
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
userm c;
printf("请输入要存款用户的身份号!\n");
scanf("%s",c.id);
printf("请输入要存款用户的用户名!\n");
scanf("%s",c.name);
printf("请输入要存款用户的密码!\n");
scanf("%s",c.pw);
printf("请输入要存款的金额!\n");
scanf("%f",&c.money);
//往请求消息队列写
c.mtype = 2; //消息类型为2,存款用
msgsnd(g_reqid,&c,sizeof(userm)-sizeof(long),0);
//读应答消息队列
RES buf2;
msgrcv(g_resid,&buf2,sizeof(buf2),2,0); //2类消息,存款用
printf("%s\n",buf2.msg);
return;
}
1. 创建消息队列的键值
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
ftok
函数用于生成一个唯一的键值,作为创建消息队列的标识符。- 第一个参数是一个路径名,用于生成键值。
- 第二个参数是一个整数,用于生成键值。
- 这里使用两个不同的路径和整数作为参数,生成两个不同的键值。
2. 打开请求消息队列
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
msgget
函数用于打开或创建一个消息队列。- 第一个参数是消息队列的键值。
- 第二个参数是标志位,
IPC_CREAT
表示如果消息队列不存在则创建它,0644
表示设置权限。 - 函数返回消息队列的标识符,如果返回值为-1,则表示打开或创建失败。
3. 打开应答消息队列
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
- 同样使用
msgget
函数打开或创建一个消息队列,这次使用第二个键值。 - 如果打开或创建失败,会打印错误信息并返回。
4. 输入存款信息
userm c;
printf("请输入要存款用户的身份号!\n");
scanf("%s",c.id);
printf("请输入要存款用户的用户名!\n");
scanf("%s",c.name);
printf("请输入要存款用户的密码!\n");
scanf("%s",c.pw);
printf("请输入要存款的金额!\n");
scanf("%f",&c.money);
- 创建一个名为
c
的userm
结构体,用于存储用户的相关信息。 - 依次输入用户的身份号、用户名、密码和存款金额。
5. 将请求写入消息队列
c.mtype = 2; //消息类型为2,存款用
msgsnd(g_reqid,&c,sizeof(userm)-sizeof(long),0);
- 将消息类型设置为2,表示这是一个存款请求。
- 使用
msgsnd
函数将c
结构体写入请求消息队列。 sizeof(userm)-sizeof(long)
表示要发送的消息的大小,减去long
类型的消息类型字段的大小。
6. 读取应答消息队列
RES buf2;
msgrcv(g_resid,&buf2,sizeof(buf2),2,0); //2类消息,存款用
printf("%s\n",buf2.msg);
- 创建一个名为
buf2
的RES
结构体,用于接收应答消息。 - 使用
msgrcv
函数从应答消息队列中读取消息。 - 第一个参数是消息队列的标识符。
- 第二个参数是接收消息的缓冲区。
- 第三个参数是接收消息的大小。
- 第四个参数是消息类型,这里为2,表示接收存款的应答消息。
- 最后一个参数是标志位,0 表示默认行为。
- 打印接收到的应答消息。
7. 返回
return;
- 结束存款业务函数的执行,返回到调用它的地方。
三、取款
void withdrawal()//取款业务
{
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
userm d;
printf("请输入要取款用户的身份号!\n");
scanf("%s",d.id);
printf("请输入要取款用户的用户名!\n");
scanf("%s",d.name);
printf("请输入要取款用户的密码!\n");
scanf("%s",d.pw);
printf("请输入要取款的金额!\n");
scanf("%f",&d.money);
//往请求消息队列写
d.mtype = 3; //消息类型为3,取款用
msgsnd(g_reqid,&d,sizeof(userm)-sizeof(long),0);
//读应答消息队列
RES buf3;
msgrcv(g_resid,&buf3,sizeof(buf3),3,0); //3类消息,取款用
printf("%s\n",buf3.msg);
return;
}
1. 创建消息队列的键值
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
ftok
函数用于生成一个唯一的键值,作为创建消息队列的标识符。- 第一个参数是一个路径名,用于生成键值。
- 第二个参数是一个整数,用于生成键值。
- 这里使用两个不同的路径和整数作为参数,生成两个不同的键值。
2. 打开请求消息队列
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
msgget
函数用于打开或创建一个消息队列。- 第一个参数是消息队列的键值。
- 第二个参数是标志位,
IPC_CREAT
表示如果消息队列不存在则创建它,0644
表示设置权限。 - 函数返回消息队列的标识符,如果返回值为-1,则表示打开或创建失败。
3. 打开应答消息队列
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
- 同样使用
msgget
函数打开或创建一个消息队列,这次使用第二个键值。 - 如果打开或创建失败,会打印错误信息并返回。
4. 输入取款信息
userm d;
printf("请输入要取款用户的身份号!\n");
scanf("%s",d.id);
printf("请输入要取款用户的用户名!\n");
scanf("%s",d.name);
printf("请输入要取款用户的密码!\n");
scanf("%s",d.pw);
printf("请输入要取款的金额!\n");
scanf("%f",&d.money);
- 创建一个名为
d
的userm
结构体,用于存储用户的相关信息。 - 依次输入用户的身份号、用户名、密码和取款金额。
5. 将请求写入消息队列
d.mtype = 3; //消息类型为3,取款用
msgsnd(g_reqid,&d,sizeof(userm)-sizeof(long),0);
- 将消息类型设置为3,表示这是一个取款请求。
- 使用
msgsnd
函数将d
结构体写入请求消息队列。 sizeof(userm)-sizeof(long)
表示要发送的消息的大小,减去long
类型的消息类型字段的大小。
6. 读取应答消息队列
RES buf3;
msgrcv(g_resid,&buf3,sizeof(buf3),3,0); //3类消息,取款用
printf("%s\n",buf3.msg);
- 创建一个名为
buf3
的RES
结构体,用于接收应答消息。 - 使用
msgrcv
函数从应答消息队列中读取消息。 - 第一个参数是消息队列的标识符。
- 第二个参数是接收消息的缓冲区。
- 第三个参数是接收消息的大小。
- 第四个参数是消息类型,这里为3,表示接收取款的应答消息。
- 最后一个参数是标志位,0 表示默认行为。
- 打印接收到的应答消息。
7. 返回
return;
- 结束取款业务函数的执行,返回到调用它的地方。
四、查询
void Inquire()//查询业务
{
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
userm e;
printf("请输入要查询用户的身份号!\n");
scanf("%s",e.id);
printf("请输入要查询用户的用户名!\n");
scanf("%s",e.name);
printf("请输入要查询用户的密码!\n");
scanf("%s",e.pw);
//printf("请输入要查询的金额!\n");
//scanf("%f",&d.money);
//往请求消息队列写
e.mtype = 4; //消息类型为4,查询用
msgsnd(g_reqid,&e,sizeof(userm)-sizeof(long),0);
//读应答消息队列
RES buf4;
msgrcv(g_resid,&buf4,sizeof(buf4),4,0); //消息类型为4,查询用
printf("%s\n",buf4.msg);
return;
}
1. 创建消息队列的键值
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
- 同样使用
ftok
函数生成两个不同的键值,用于创建消息队列。
2. 打开请求消息队列
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
- 使用
msgget
函数打开或创建请求消息队列。
3. 打开应答消息队列
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
- 同样使用
msgget
函数打开或创建应答消息队列。
4. 输入查询信息
userm e;
printf("请输入要查询用户的身份号!\n");
scanf("%s",e.id);
printf("请输入要查询用户的用户名!\n");
scanf("%s",e.name);
printf("请输入要查询用户的密码!\n");
scanf("%s",e.pw);
- 创建一个名为
e
的userm
结构体,用于存储查询用户的相关信息。 - 依次输入用户的身份号、用户名和密码。
5. 将请求写入消息队列
e.mtype = 4; //消息类型为4,查询用
msgsnd(g_reqid,&e,sizeof(userm)-sizeof(long),0);
- 将消息类型设置为4,表示这是一个查询请求。
- 使用
msgsnd
函数将e
结构体写入请求消息队列。 sizeof(userm)-sizeof(long)
表示要发送的消息的大小,减去long
类型的消息类型字段的大小。
6. 读取应答消息队列
RES buf4;
msgrcv(g_resid,&buf4,sizeof(buf4),4,0); //消息类型为4,查询用
printf("%s\n",buf4.msg);
- 创建一个名为
buf4
的RES
结构体,用于接收应答消息。 - 使用
msgrcv
函数从应答消息队列中读取消息。 - 第一个参数是消息队列的标识符。
- 第二个参数是接收消息的缓冲区。
- 第三个参数是接收消息的大小。
- 第四个参数是消息类型,这里为4,表示接收查询的应答消息。
- 最后一个参数是标志位,0 表示默认行为。
- 打印接收到的应答消息。
7. 返回
return;
- 结束查询业务函数的执行,返回到调用它的地方。
五、转账
void Transfer()//转账业务
{
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
userm f1,f2;
printf("请输入转账用户的身份号!\n");
scanf("%s",f1.id);
printf("请输入转账用户的用户名!\n");
scanf("%s",f1.name);
printf("请输入转账用户的密码!\n");
scanf("%s",f1.pw);
printf("请输入要转账的金额!\n");
scanf("%f",&f1.money);
printf("请输入被转账用户的身份号!\n");
scanf("%s",f2.id);
//往请求消息队列写
f1.mtype = 5; //消息类型为5,转账用,第一条消息,转账用户用
msgsnd(g_reqid,&f1,sizeof(userm)-sizeof(long),0);
f2.mtype = 55; //消息类型为55,转账用,第二条消息,被转账用户用
msgsnd(g_reqid,&f2,sizeof(userm)-sizeof(long),0);
//读应答消息队列
RES buf3;
msgrcv(g_resid,&buf3,sizeof(buf3),5,0); //5类消息,转账用
printf("%s\n",buf3.msg);
RES buf4;
msgrcv(g_resid,&buf4,sizeof(buf4),55,0); //55类消息,转账用
printf("%s\n",buf4.msg);
return;
}
1. 创建消息队列的键值
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
- 同样使用
ftok
函数生成两个不同的键值,用于创建消息队列。
2. 打开请求消息队列
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
- 使用
msgget
函数打开或创建请求消息队列。
3. 打开应答消息队列
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
- 同样使用
msgget
函数打开或创建应答消息队列。
4. 输入转账用户信息
userm f1,f2;
printf("请输入转账用户的身份号!\n");
scanf("%s",f1.id);
printf("请输入转账用户的用户名!\n");
scanf("%s",f1.name);
printf("请输入转账用户的密码!\n");
scanf("%s",f1.pw);
printf("请输入要转账的金额!\n");
scanf("%f",&f1.money);
- 创建两个名为
f1
和f2
的userm
结构体,分别用于存储转账用户和被转账用户的相关信息。 - 依次输入转账用户的身份号、用户名、密码和转账金额。
5. 将请求写入消息队列
f1.mtype = 5; //消息类型为5,转账用,第一条消息,转账用户用
msgsnd(g_reqid,&f1,sizeof(userm)-sizeof(long),0);
f2.mtype = 55; //消息类型为55,转账用,第二条消息,被转账用户用
msgsnd(g_reqid,&f2,sizeof(userm)-sizeof(long),0);
- 将消息类型设置为5和55,表示这是转账请求的两条消息。
- 使用
msgsnd
函数将f1
和f2
结构体分别写入请求消息队列。 sizeof(userm)-sizeof(long)
表示要发送的消息的大小,减去long
类型的消息类型字段的大小。
6. 读取应答消息队列
RES buf3;
msgrcv(g_resid,&buf3,sizeof(buf3),5,0); //5类消息,转账用
printf("%s\n",buf3.msg);
RES buf4;
msgrcv(g_resid,&buf4,sizeof(buf4),55,0); //55类消息,转账用
printf("%s\n",buf4.msg);
- 创建两个名为
buf3
和buf4
的RES
结构体,用于接收应答消息。 - 使用
msgrcv
函数从应答消息队列中读取消息。 - 第一个参数是消息队列的标识符。
- 第二个参数是接收消息的缓冲区。
- 第三个参数是接收消息的大小。
- 第四个参数是消息类型,这里分别为5和55,表示接收转账的应答消息。
- 最后一个参数是标志位,0 表示默认行为。
- 打印接收到的应答消息。
7. 返回
return;
- 结束转账业务函数的执行,返回到调用它的地方。
六、注销
void Logout()
{
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
userm b;
printf("请输入要注销用户的身份号!\n");
scanf("%s",b.id);
printf("请输入要注销用户的用户名!\n");
scanf("%s",b.name);
printf("请输入要注销用户的密码!\n");
scanf("%s",b.pw);
printf("请输入要注销用户的余额!\n");
scanf("%f",&b.money);
//往请求消息队列写
b.mtype = 6; //消息类型为6,注销用
msgsnd(g_reqid,&b,sizeof(userm)-sizeof(long),0);
//读应答消息队列
RES buf1;
msgrcv(g_resid,&buf1,sizeof(buf1),6,0); //6类消息,注销用
printf("%s\n",buf1.msg);
return;
}
1. 创建消息队列的键值
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
- 同样使用
ftok
函数生成两个不同的键值,用于创建消息队列。
2. 打开请求消息队列
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
- 使用
msgget
函数打开或创建请求消息队列。
3. 打开应答消息队列
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
- 同样使用
msgget
函数打开或创建应答消息队列。
4. 输入注销用户信息
userm b;
printf("请输入要注销用户的身份号!\n");
scanf("%s",b.id);
printf("请输入要注销用户的用户名!\n");
scanf("%s",b.name);
printf("请输入要注销用户的密码!\n");
scanf("%s",b.pw);
printf("请输入要注销用户的余额!\n");
scanf("%f",&b.money);
- 创建名为
b
的userm
结构体,用于存储注销用户的相关信息。 - 依次输入要注销用户的身份号、用户名、密码和余额。
5. 将请求写入消息队列
b.mtype = 6; //消息类型为6,注销用
msgsnd(g_reqid,&b,sizeof(userm)-sizeof(long),0);
- 将消息类型设置为6,表示这是注销请求的消息。
- 使用
msgsnd
函数将b
结构体写入请求消息队列。 sizeof(userm)-sizeof(long)
表示要发送的消息的大小,减去long
类型的消息类型字段的大小。
6. 读取应答消息队列
RES buf1;
msgrcv(g_resid,&buf1,sizeof(buf1),6,0); //6类消息,注销用
printf("%s\n",buf1.msg);
- 创建名为
buf1
的RES
结构体,用于接收应答消息。 - 使用
msgrcv
函数从应答消息队列中读取消息。 - 第一个参数是消息队列的标识符。
- 第二个参数是接收消息的缓冲区。
- 第三个参数是接收消息的大小。
- 第四个参数是消息类型,这里为6,表示接收注销的应答消息。
- 最后一个参数是标志位,0 表示默认行为。
- 打印接收到的应答消息。
7. 返回
return;
- 结束注销用户业务函数的执行,返回到调用它的地方。
整体代码
#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>
int g_reqid; //作为请求的消息队列的返回id
int g_resid; //作为应答消息队列的返回id
typedef struct msgbuf{
long mtype; //消息类型
char id[100]; //账户
char name[256]; //用户名
char pw[9]; //密码
float money; //银行卡余额
}userm;
typedef struct tag_OpenRespond{
long type;
char id[100]; //账户
char msg[256];
float money; //银行卡余额
}RES; //让客户端从应答消息队列读到的反馈存到这里
void menu();
void Account();//开户
void Deposit();//存款
void withdrawal();//取款
void Inquire();//查询
void Transfer();//转账
void Logout();//注销
int main()
{
while(1)
{
menu();
int a;
printf("请输入要执行的操作!\n");
scanf("%d",&a);
switch(a)
{
case 1:Account();break;//开户
case 2:Deposit();break;//存款
case 3:withdrawal();break;//取款
case 4:Inquire();break;//查询
case 5:Transfer();break;//转账
case 6:Logout();break;//注销
case 7:
return 0;
}
}
}
void Account()
{
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
userm a;
printf("请输入要注册的身份号!\n");
scanf("%s",a.id);
printf("请输入要注册的用户名!\n");
scanf("%s",a.name);
printf("请输入要注册的密码!\n");
scanf("%s",a.pw);
printf("请输入要注册的余额!\n");
scanf("%f",&a.money);
//往请求消息队列写
a.mtype = 1; //消息类型为1,开户用
msgsnd(g_reqid,&a,sizeof(userm)-sizeof(long),0);
//读应答消息队列
RES buf;
msgrcv(g_resid,&buf,sizeof(buf),1,0); //1类消息,开户用
printf("%s\n",buf.msg);
return;
}
void Logout()
{
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
userm b;
printf("请输入要注销用户的身份号!\n");
scanf("%s",b.id);
printf("请输入要注销用户的用户名!\n");
scanf("%s",b.name);
printf("请输入要注销用户的密码!\n");
scanf("%s",b.pw);
printf("请输入要注销用户的余额!\n");
scanf("%f",&b.money);
//往请求消息队列写
b.mtype = 6; //消息类型为6,注销用
msgsnd(g_reqid,&b,sizeof(userm)-sizeof(long),0);
//读应答消息队列
RES buf1;
msgrcv(g_resid,&buf1,sizeof(buf1),6,0); //6类消息,注销用
printf("%s\n",buf1.msg);
return;
}
void Deposit()//存款业务
{
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
userm c;
printf("请输入要存款用户的身份号!\n");
scanf("%s",c.id);
printf("请输入要存款用户的用户名!\n");
scanf("%s",c.name);
printf("请输入要存款用户的密码!\n");
scanf("%s",c.pw);
printf("请输入要存款的金额!\n");
scanf("%f",&c.money);
//往请求消息队列写
c.mtype = 2; //消息类型为2,存款用
msgsnd(g_reqid,&c,sizeof(userm)-sizeof(long),0);
//读应答消息队列
RES buf2;
msgrcv(g_resid,&buf2,sizeof(buf2),2,0); //2类消息,存款用
printf("%s\n",buf2.msg);
return;
}
void withdrawal()//取款业务
{
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
userm d;
printf("请输入要取款用户的身份号!\n");
scanf("%s",d.id);
printf("请输入要取款用户的用户名!\n");
scanf("%s",d.name);
printf("请输入要取款用户的密码!\n");
scanf("%s",d.pw);
printf("请输入要取款的金额!\n");
scanf("%f",&d.money);
//往请求消息队列写
d.mtype = 3; //消息类型为3,取款用
msgsnd(g_reqid,&d,sizeof(userm)-sizeof(long),0);
//读应答消息队列
RES buf3;
msgrcv(g_resid,&buf3,sizeof(buf3),3,0); //3类消息,取款用
printf("%s\n",buf3.msg);
return;
}
void Inquire()
{
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
userm e;
printf("请输入要查询用户的身份号!\n");
scanf("%s",e.id);
printf("请输入要查询用户的用户名!\n");
scanf("%s",e.name);
printf("请输入要查询用户的密码!\n");
scanf("%s",e.pw);
//printf("请输入要查询的金额!\n");
//scanf("%f",&d.money);
//往请求消息队列写
e.mtype = 4; //消息类型为4,查询用
msgsnd(g_reqid,&e,sizeof(userm)-sizeof(long),0);
//读应答消息队列
RES buf4;
msgrcv(g_resid,&buf4,sizeof(buf4),4,0); //消息类型为4,查询用
printf("%s\n",buf4.msg);
return;
}
void Transfer()//转账业务
{
key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
perror("msgget");
return;
}
g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
perror("msgget");
return;
}
userm f1,f2;
printf("请输入转账用户的身份号!\n");
scanf("%s",f1.id);
printf("请输入转账用户的用户名!\n");
scanf("%s",f1.name);
printf("请输入转账用户的密码!\n");
scanf("%s",f1.pw);
printf("请输入要转账的金额!\n");
scanf("%f",&f1.money);
printf("请输入被转账用户的身份号!\n");
scanf("%s",f2.id);
//往请求消息队列写
f1.mtype = 5; //消息类型为5,转账用,第一条消息,转账用户用
msgsnd(g_reqid,&f1,sizeof(userm)-sizeof(long),0);
f2.mtype = 55; //消息类型为55,转账用,第二条消息,被转账用户用
msgsnd(g_reqid,&f2,sizeof(userm)-sizeof(long),0);
//读应答消息队列
RES buf3;
msgrcv(g_resid,&buf3,sizeof(buf3),5,0); //5类消息,转账用
printf("%s\n",buf3.msg);
RES buf4;
msgrcv(g_resid,&buf4,sizeof(buf4),55,0); //55类消息,转账用
printf("%s\n",buf4.msg);
return;
}
void menu()
{
printf("********欢迎来到小黑银行!************\n");
printf("**************1.开户******************\n");
printf("**************2.存款******************\n");
printf("**************3.取款******************\n");
printf("**************4.查询******************\n");
printf("**************5.转账******************\n");
printf("**************6.销户******************\n");
printf("**************7.退出******************\n");
}