项目需求:
主要分为两人大模块:
客户端
1、进入时的功能开户、销户、登录、解锁
开户:输入姓名、身份证号、设置密码,如果开户成功,则服务器上保存一个账号信号(一个账号存一个文件,文件名建议是账号)。
销户:输入帐号、密码,服务器询问是否确认销户,如果确认则服务器删除帐号文件,并记录帐号。(我没实现)
登录:输入账号、密码,三次错误账号锁定。
解锁:输入账号、身份证号解锁。
2、登录成功:存钱、取钱、转账、查询、修改密码
存钱:输入存钱金额
取钱:输入取钱金额
转账:目标帐号和要转的金额
查询:不需要输入数据
修改密码:原密码和新密码
服务器
如果识别功能:根据消息的类型识别客户端请求的功能。
开启服务各项功能的子进程
各进程按照消息类型接收消息
直接先上图:
打开2个终端,一个 make编译所有文件
然后运行 ./server(服务端)
另一个终端运行 ./client(客户端)
切记不要关闭服务端。
接下来在客户端进行操作。
1、开户(客户端)
(服务端)会输出相关信息
2、销户
(客户端)
(服务端)
3、登录
(客户端)
(服务端)
登录后(子功能)
具体就不在列举了,下面提供部分源码,具体请移步码云:传送门,GitHub:传送门
server.c
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include "struct.h"
#include "tools.h"
// 2个消息队列
static int msgid_ctos;
static int msgid_stoc;
// 存储子进程ID
static pid_t sub_pid[9];
// SIGINT信号处理
void sigint(int sig)
{
// 对msqid标识的消息队列执行cmd操作
msgctl(msgid_ctos, IPC_RMID, NULL);
msgctl(msgid_stoc, IPC_RMID, NULL);
int i = 0;
for(i=0; i<9; i++)
{
kill(sub_pid[i], SIGKILL);
}
}
int main()
{
// 处理信号 SIGINT(2) 终端中断符信号
signal(SIGINT, sigint);
// int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msgctl(msgid_ctos, IPC_RMID, NULL);
msgctl(msgid_stoc, IPC_RMID, NULL);
// IPC_CREAT 创建消息队列,IPC_EXCL 如果存在则创建失败
// IPC键值,由ftok函数自动生成
msgid_ctos = msgget(ftok(".", 100), IPC_CREAT|IPC_EXCL|0644);
msgid_stoc = msgget(ftok(".", 200), IPC_CREAT|IPC_EXCL|0644);
// login open save take transf select change destory unlock
// 创建一个新的进程
sub_pid[0] = vfork();
if(0 == sub_pid[0])
{
execl("login","login", NULL);
printf("登陆子进程创建成功...\n");
}
sub_pid[1] = vfork();
if(0 == sub_pid[1])
{
execl("open","open", NULL);
printf("开户子进程创建成功...\n");
}
sub_pid[2] = vfork();
if(0 == sub_pid[2])
{
execl("save","save", NULL);
}
sub_pid[3] = vfork();
if(0 == sub_pid[3])
{
execl("take","take", NULL);
}
sub_pid[4] = vfork();
if(0 == sub_pid[4])
{
execl("transf","transf", NULL);
}
sub_pid[5] = vfork();
if(0 == sub_pid[5])
{
execl("select","select", NULL);
}
sub_pid[6] = vfork();
if(0 == sub_pid[6])
{
execl("change","change", NULL);
}
sub_pid[7] = vfork();
if(0 == sub_pid[7])
{
execl("destory","destory", NULL);
}
sub_pid[8] = vfork();
if(0 == sub_pid[8])
{
execl("unlock","unlock", NULL);
}
//pause();
while(-1 != wait(NULL));
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
#include "struct.h"
#include "tools.h"
//#include "msg_queue.c"
static long online = 0;
static int lock = 0;
int msgid_ctos;
int msgid_stoc;
// 初始化
int init();
// 创建账户
void open_acc();
// 销毁账户
void destory();
// 登录
void login();
// 解锁
void unlock();
// 用户菜单
void user_menu(void);
// 主菜单
void menu(void);
// 存钱
void save();
// 取钱
void take();
// 转账
void transf();
// 查询余额
void select_money();
// 修改密码
void change_pw();
int main()
{
init();
menu();
}
// 初始化
int init()
{
//msgctl(msgid_ctos,IPC_RMID,NULL);
// 创建消息队列
msgid_ctos = msgget(ftok(".",100),0);
if(0 > msgid_ctos)
{
perror("msgget");
return -1;
}
msgid_stoc = msgget(ftok(".",200),0);
if(0 > msgid_stoc)
{
perror("msgget");
return -1;
}
return 0;
}
// 登录
void login()//0
{
if(lock >= 3)
{
printf("您已被锁定,请解锁\n");
getchar();
return;
}
Account acc = {};
Msg msg = {110};
printf("请输入帐号:");
scanf("%ld",&acc.user);
getchar();
printf("请输入密码:");
get_str(acc.pw,20);
msg.acc = acc;
msgsnd(msgid_ctos,&msg,sizeof(Msg)-sizeof(msg.type),0);
Msg msg2 = {};
// 接收消息
msgrcv(msgid_stoc,&msg2,sizeof(Msg),220,MSG_NOERROR);
if(acc.user == msg2.acc.user)
{
online = acc.user;
printf("%ld,登陆成功\n",online);
getch();
user_menu();
}
else
{
lock++;
printf("帐号或密码错误\n");
getch();
}
}
// 创建账户
void open_acc()//1
{
Account acc = {};
Msg msg = {111};
printf("请输入姓名:");
get_str(acc.name,20);
printf("请输入身份证:");
get_str(acc.id,20);
printf("请输入密码:");
get_str(acc.pw,20);
msg.acc = acc;
//printf("msg:%s\n",msg.acc.name);
msgsnd(msgid_ctos,&msg,sizeof(Msg)-sizeof(msg.type),0);
Msg msg2 = {};
// 接收消息
msgrcv(msgid_stoc,&msg2,sizeof(Msg),221,MSG_NOERROR);
printf("msg2:%s,acc:%s\n",msg2.acc.name,acc.name);
if(strcmp(acc.name,msg2.acc.name) == 0)
{
//printf("%s\n",msg2.acc.name);
//printf("%s\n",msg2.acc.id);
printf("帐号:%ld,开户成功\n",msg2.acc.user);
}
else
{
printf("开户失败\n");
}
getch();
}
// 存钱
void save()//2
{
Account acc = {};
Msg msg = {112};
//printf("当前用户:%ld\n",online);
printf("请输入存款金额:");
scanf("%lf",&acc.money);
getchar();
acc.user = online;
msg.acc = acc;
msgsnd(msgid_ctos,&msg,sizeof(Msg)-sizeof(msg.type),0);
Msg msg2 = {};
// 接收消息
msgrcv(msgid_stoc,&msg2,sizeof(Msg),222,MSG_NOERROR);
if(msg2.acc.user == online)
{
printf("存钱成功\n");
}
else
{
printf("存钱失败\n");
}
getch();
}
// 取钱
void take()//3
{
Account acc = {};
Msg msg = {113};
printf("请输入取款金额:");
scanf("%lf",&acc.money);
getchar();
acc.user = online;
msg.acc = acc;
msgsnd(msgid_ctos,&msg,sizeof(Msg)-sizeof(msg.type),0);
Msg msg2 = {};
// 接收消息
msgrcv(msgid_stoc,&msg2,sizeof(Msg),223,MSG_NOERROR);
if(msg2.acc.user == online)
{
printf("取钱成功\n");
}
else if(msg2.acc.user == online + 2)
{
printf("余额不足,请充值\n");
}
else
{
printf("取钱失败\n");
}
getch();
}
// 转账
void transf()//4
{
Account acc = {};
Msg msg = {114};
printf("请输入转帐金额:");
scanf("%lf",&acc.money);
getchar();
acc.user = online;
msg.acc = acc;
msg.flag = 0;
msgsnd(msgid_ctos,&msg,sizeof(Msg)-sizeof(msg.type),0);
Msg msg2 = {};
// 接收消息
msgrcv(msgid_stoc,&msg2,sizeof(Msg),224,MSG_NOERROR);
if(msg2.flag == 0)
{
printf("请输入要转帐的帐号:");
scanf("%ld",&acc.user);
getchar();
msg.acc = acc;
msg.flag = 1;
msgsnd(msgid_ctos,&msg,sizeof(Msg)-sizeof(msg.type),0);
// 接收消息
msgrcv(msgid_stoc,&msg2,sizeof(Msg),224,MSG_NOERROR);
if(msg2.flag == 2)
{
printf("转帐成功\n");
}
else
{
printf("转帐失败\n");
}
}
else
{
printf("余额不足,请充值\n");
}
getch();
}
// 查询余额
void select_money()//5
{
Account acc = {};
Msg msg = {115};
acc.user = online;
msg.acc = acc;
msgsnd(msgid_ctos,&msg,sizeof(Msg)-sizeof(msg.type),0);
Msg msg2 = {};
// 接收消息
msgrcv(msgid_stoc,&msg2,sizeof(Msg),225,MSG_NOERROR);
if(msg2.acc.user == online)
{
printf("余额:%.2lf\n",msg2.acc.money);
}
else
{
printf("查询失败\n");
}
getch();
}
// 修改密码
void change_pw()//6
{
Account acc = {};
Msg msg = {116};
printf("请输入新密码:");
get_str(acc.pw,20);
acc.user = online;
msg.acc = acc;
msgsnd(msgid_ctos,&msg,sizeof(Msg)-sizeof(msg.type),0);
Msg msg2 = {};
// 接收消息
msgrcv(msgid_stoc,&msg2,sizeof(Msg),226,MSG_NOERROR);
if(msg2.acc.user == online)
{
printf("改密成功\n");
}
else
{
printf("改密失败\n");
}
getch();
}
// 销毁账户
void destory()//7
{
Account acc = {};
Msg msg = {117};
printf("请输入销户帐号:");
scanf("%ld",&acc.user);
getchar();
printf("请输入姓名:");
get_str(acc.name,20);
printf("请输入身份证:");
get_str(acc.id,20);
msg.acc = acc;
msgsnd(msgid_ctos,&msg,sizeof(Msg)-sizeof(msg.type),0);
Msg msg2 = {};
// 接收消息
msgrcv(msgid_stoc,&msg2,sizeof(Msg),227,MSG_NOERROR);
if(msg2.acc.user == 0)
{
printf("销户成功\n");
}
else if(msg2.acc.user == 1)
{
printf("相关信息错误\n");
}
else if(msg2.acc.user == 2)
{
printf("帐号不存在\n");
}
getch();
}
// 解锁账户
void unlock()//8
{
if(lock < 3)
{
printf("您没有被锁定,sorry\n");
getchar();
return;
}
Account acc = {};
Msg msg = {118};
printf("请输入帐号:");
scanf("%ld",&acc.user);
getchar();
printf("请输入姓名:");
get_str(acc.name,20);
printf("请输入身份证:");
get_str(acc.id,20);
msg.acc = acc;
msgsnd(msgid_ctos,&msg,sizeof(Msg)-sizeof(msg.type),0);
//printf("消息已发送到队列\n");
Msg msg2 = {};
// 接收消息
msgrcv(msgid_stoc,&msg2,sizeof(Msg),228,MSG_NOERROR);
//printf("已接收到队列的消息\n");
printf("in:%ld,back:%ld\n",acc.user,msg2.acc.user);
if(acc.user == msg2.acc.user)
{
printf("%ld,解锁成功\n",acc.user);
lock = 0;
online = acc.user;
change_pw();
}
else
{
printf("相关信息错误\n");
getch();
}
/* long user = 0;
char id[20] = {};
char name[20] = {};
printf("请输入要解锁的帐号:");
scanf("%ld",&user);
getchar();
char path[50] = "./data/";
char ex[8] = ".dat";
sprintf(path,"%s%ld%s",path,user,ex);
if(0 == access(path,F_OK))
{
Account buf = {};
int fd = open(path,O_RDWR);
if(0 != read(fd,&buf,sizeof(Account)))
{
char name[20] = {};
char id[20] = {};
printf("请输入此帐号开户姓名:");
get_str(name,20);
printf("请输入此帐号开户身份证:");
get_str(id,20);
if(strcmp(name,buf.name) == 0 && strcmp(id,buf.id) == 0)
{
online = user;
change_pw();
lock = 0;
}
else
{
printf("输入信息有误\n");
close(fd);
getch();
}
}
else
{
printf("读取信息失败\n");
getch();
}
}
else
{
printf("此帐号不存在\n");
getch();
}
*/
}
// 用户菜单
void user_menu(void)
{
while(1)
{
system("clear");
printf("--- 银行 ---\n");
printf("1、 存钱\n");
printf("2、 取钱\n");
printf("3、 转帐\n");
printf("4、 查询\n");
printf("5、 改密\n");
printf("0、 返回\n");
switch(get_cmd('0','5'))
{
case '1':save(); break;
case '2':take(); break;
case '3':transf(); break;
case '4':select_money(); break;
case '5':change_pw();break;
case '0':return;
}
}
}
// 主菜单
void menu(void)
{
while(1)
{
system("clear");
printf("--- 银行 ---\n");
printf("1、 开户\n");
printf("2、 销户\n");
printf("3、 登陆\n");
printf("4、 解锁\n");
printf("0、 退出\n");
switch(get_cmd('0','4'))
{
case '1':open_acc(); break;
case '2':destory(); break;
case '3':login(); break;
case '4':unlock(); break;
case '0':return;
}
}
}