在之前写的博客里面提到了上一个项目简易聊天室的问题,在这个银行管理系统上面得到了解决,通过服务器的链表将用户输入的账号密码储存起来,然后在服务器不退出的情况下,实现用户的查询、存钱、取钱、转账、改密码、销户等功能,并将其交易记录写入了Mysql的数据库中。服务器即使退出,丢失账号密码但是交易记录还在。其实账号密码也是应当存储在数据库中,这样账户密码也不会丢失,但是为了练习链表将其写在了链表中。
下面写的是安装MySQL的数据库的命令。
apt-get install mysql-server //需要自己指定密码
apt-get install mysql-client
apt-get install libmysqlclient-dev//支持C语言API
客户端我通过设置termios结构体中的c_lflag设置来关闭回显,保证密码安全,通过查找资料封装了一个函数来管理是否回显。
/*************************************************************************
> 文件路径: client.c
> 作者: Moliam
> 邮箱: [email protected]
> 文件创建时间: 2019年03月20日 星期三 14时47分52秒
************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include //由于我修改了vim的配置,所以会出现没有必要的头文件
#define ECHOFLAGS (ECHO | ECHOE | ECHOK | ECHONL)//回显相关宏定义
#define PORT 9709
int sockfd;
int text_fd;
//char *IP = "192.168.1.190";
char *IP = "192.168.15.2";//服务器IP地址
typedef struct sockaddr AD;
char acc[30]={0};//存放账户
char cmd_buf[30]={0};//存放命令
char dat_buf[100]={0};//存放数据
int set_disp_mode(int fd,int option);//是否回显函数
int getpasswd(char* passwd, int size);//获取终端输入函数
void err(const char *buf,int line);//出错函数
void Init(void);//初始化客户端
void Service(void);//匹配帐号密码
void menu(void);//菜单
void enquiry(void);//查询余额
void save(void);//存钱
void withdraw(void);//取钱
void modpw(void);//改密
void trans(void);//转账
void logout(void);//注销
void __exit(void);
int main(void)
{
Init();
Service();
menu();//
return 0;
}
void menu(void)
{
//0查询 1存款 2取款 3转账 4改密 5销户 6退出
int opt=0;
while(1)
{
printf("*********************************\n");
printf(" 按0查询 \n");
printf(" 按1存款 \n");
printf(" 按2取款 \n");
printf(" 按3转账 \n");
printf(" 按4改密 \n");
printf(" 按5销户 \n");
printf(" 按6退出 \n");
printf("*********************************\n");
repeat: printf("请输入你需要进行的操作:\n");
scanf("%d",&opt);
if (opt > 6 && opt < 0)
{
printf("输入错误,请重新输入!\n");
goto repeat;
}
switch(opt)
{
case 0:enquiry();break;
case 1:save();break;
case 2:withdraw();break;
case 3:trans();break;
case 4:modpw();break;
case 5:logout();break;
case 6:__exit();return ;
}
}
}
void enquiry(void)
{
sprintf(cmd_buf,"0");
text_fd = send(sockfd,cmd_buf,strlen(cmd_buf),0);//发送命令
if(text_fd == -1)
err("send",__LINE__);
text_fd = recv(sockfd,dat_buf,sizeof(dat_buf),0);//接受余额
if(text_fd == -1)
err("recv",__LINE__);
printf("当前余额为%s\n",dat_buf);
memset(dat_buf,0,sizeof(dat_buf));
}
void save(void)
{
double money = 0;
sprintf(cmd_buf,"1");
text_fd = send(sockfd,cmd_buf,strlen(cmd_buf),0);//发送命令
if(text_fd == -1)
err("send",__LINE__);
printf("请输入你要存的数目:\n");
scanf("%lf",&money);
sprintf(dat_buf,"%.2f",money);
text_fd = send(sockfd,dat_buf,strlen(dat_buf),0);//发送数目
if(text_fd == -1)
err("send",__LINE__);
memset(dat_buf,0,sizeof(dat_buf));
text_fd = recv(sockfd,dat_buf,sizeof(dat_buf),0);//接收是否成功
if(text_fd == -1)
err("recv",__LINE__);
if(strcmp(dat_buf,"correct") != 0)
{
printf("aha,failure!\n");
}
memset(dat_buf,0,sizeof(dat_buf));
enquiry();
}
void withdraw(void)
{
float money = 0;
sprintf(cmd_buf,"2");
text_fd = send(sockfd,cmd_buf,strlen(cmd_buf),0);//发送命令
if(text_fd == -1)
err("send",__LINE__);
printf("请输入你要提现的数目:\n");
scanf("%f",&money);
sprintf(dat_buf,"%.2f",money);
text_fd = send(sockfd,dat_buf,strlen(dat_buf),0);//发送数目
if(text_fd == -1)
err("send",__LINE__);
memset(dat_buf,0,sizeof(dat_buf));
text_fd = recv(sockfd,dat_buf,sizeof(dat_buf),0);//接收是否成功
if(text_fd == -1)
err("recv",__LINE__);
if(strcmp(dat_buf,"correct") != 0)
{
printf("aha,failure!\n");
}
memset(dat_buf,0,sizeof(dat_buf));
enquiry();
}
void trans(void)
{
float money = 0;
char name[20];
sprintf(cmd_buf,"3");
text_fd = send(sockfd,cmd_buf,strlen(cmd_buf),0);//发送命令
err: memset(name,0,sizeof(name));
if(text_fd == -1)
err("send",__LINE__);
printf("请输入你要转账的账户(按quit退出):\n");
scanf("%s",name);
getchar();
if(strcmp(name,"quit") == 0)
{text_fd = send(sockfd,name,strlen(name),0);return;}
text_fd = send(sockfd,name,strlen(name),0);//发送名字
if(text_fd == -1)
err("send",__LINE__);
memset(dat_buf,0,sizeof(dat_buf));
text_fd = recv(sockfd,dat_buf,sizeof(dat_buf),0);//接收是否存在
if(text_fd == -1)
err("recv",__LINE__);
if(strcmp(dat_buf,"correct") != 0)
{
printf("aha,failure!Not such the person!\n");
goto err;
}
memset(dat_buf,0,sizeof(dat_buf));
scanf("%f",&money);
sprintf(dat_buf,"%.2f",money);
text_fd = send(sockfd,dat_buf,strlen(dat_buf),0);//发送数目
if(text_fd == -1)
err("send",__LINE__);
text_fd = recv(sockfd,dat_buf,sizeof(dat_buf),0);//接收是否成功
if(text_fd == -1)
err("recv",__LINE__);
if(strcmp(dat_buf,"correct") != 0)
{
printf("aha,failure!You have no money!\n");
}
memset(dat_buf,0,sizeof(dat_buf));
enquiry();
}
void modpw(void)
{
char *p,passwd[20],com[20];
sprintf(cmd_buf,"4");
text_fd = send(sockfd,cmd_buf,strlen(cmd_buf),0);//发送命令
if(text_fd == -1)
err("send",__LINE__);
set_disp_mode(STDIN_FILENO,0);//关闭回显
getchar();
getpasswd(passwd, sizeof(passwd));
p=passwd;
while(*p!='\n')
p++;
*p='\0';
printf("\n");
getpasswd(com, sizeof(com));
p=com;
while(*p!='\n')
p++;
*p='\0';
printf("\n");
set_disp_mode(STDIN_FILENO,1);//打开回显
if(strcmp(passwd,com) != 0)
{
printf("两次输入密码不一致!!\n");
return ;
}
text_fd = send(sockfd,passwd,strlen(passwd),0);//发送密码
if(text_fd == -1)
err("send",__LINE__);
text_fd = recv(sockfd,dat_buf,sizeof(dat_buf),0);//接收是否成功
if(text_fd == -1)
err("recv",__LINE__);
if(strcmp(dat_buf,"correct") != 0)
{
printf("aha,failure!\n");
}
memset(dat_buf,0,sizeof(dat_buf));
}
void logout(void)
{
sprintf(cmd_buf,"5");
text_fd = send(sockfd,cmd_buf,strlen(cmd_buf),0);//发送命令
if(text_fd == -1)
err("send",__LINE__);
text_fd = recv(sockfd,dat_buf,sizeof(dat_buf),0);//接收是否成功
if(text_fd == -1)
err("recv",__LINE__);
if(strcmp(dat_buf,"correct") != 0)
{
printf("aha,failure!\n");
}
memset(dat_buf,0,sizeof(dat_buf));
exit(-1);
}
void __exit(void)
{
sprintf(cmd_buf,"6");
text_fd = send(sockfd,cmd_buf,strlen(cmd_buf),0);//发送命令
if(text_fd == -1)
err("send",__LINE__);
exit(-1);
}
void Service(void)
{
char *p,passwd[20];
err:
printf("请输入你的帐号(无该帐号自动注册):");
scanf("%s",acc);
getchar();//读走回车
if(strcmp(acc,"quit") == 0)//为了防止误操作进入转账页面
{
printf("创建失败,账户已存在\n");
goto err;
}
set_disp_mode(STDIN_FILENO,0);
getpasswd(passwd, sizeof(passwd));
p=passwd;
while(*p!='\n')
p++;
*p='\0';
set_disp_mode(STDIN_FILENO,1);
text_fd = send(sockfd,acc,strlen(acc),0);
if(text_fd == -1)
err("send",__LINE__);
sleep(1);
text_fd = send(sockfd,passwd,strlen(passwd),0);
if(text_fd == -1)
err("send",__LINE__);
char mod_buf[20];
memset(mod_buf,0,sizeof(mod_buf));
text_fd = recv(sockfd,mod_buf,sizeof(mod_buf),0);
if(text_fd == -1)
err("recv",__LINE__);
printf("%s\n",mod_buf);
if(strcmp(mod_buf,"correct") != 0)
{
printf("帐号密码输入错误,请重新输入!\n");
goto err;
}
}
void Init(void)
{
sockfd = socket(PF_INET,SOCK_STREAM,0);
if(sockfd == -1)
err("socket",__LINE__);
struct sockaddr_in addr;
addr.sin_family = PF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr(IP);
if(connect(sockfd,(AD*)&addr,sizeof(addr)) == -1)
err("connect",__LINE__);
printf("客户端初始化成功!\n");
}
void err(const char *buf,int line)
{
fprintf(stderr,"出错行号是%d\n",line);
perror(buf);
exit(-1);
}
//函数set_disp_mode用于控制是否开启输入回显功能
//如果option为0,则关闭回显,为1则打开回显
int set_disp_mode(int fd,int option)
{
int err;
struct termios term;
if(tcgetattr(fd,&term)==-1)
{
perror("不能获得终端属性!\n");
return 1;
}
if(option)
term.c_lflag|=ECHOFLAGS;
else
term.c_lflag &=~ECHOFLAGS;
err=tcsetattr(fd,TCSAFLUSH,&term);
if(err==-1 && err==EINTR)
{
perror("不能设置终端属性!\n");
return 1;
}
return 0;
}
int getpasswd(char* passwd, int size)//获得密码函数
{
int c;
int n = 0;
printf("请输入密码:");
do
{
c=getchar();
if (c != '\n'|c!='\r')
{
passwd[n++] = c;
}
}while(c != '\n' && c !='\r' && n < (size - 1));//当读到回车,换行或者超出了
passwd[n] = '\0';
return n;
}
服务器通过链表来存储账号密码,然后将交易记录放在了数据库中,因为我建立的数据库名字时band_msg,数据库的建立顺序应先于服务器执行代码,不然会出现链接数据库错误的问题
/*************************************************************************
> 文件路径: service.c
> 作者: Moliam
> 邮箱: [email protected]
> 文件创建时间: 2019年03月20日 星期三 14时47分43秒
************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX_CLI 256
#define PORT 9709
int sockfd;
int text_fd;
//char *IP = "192.168.1.190";
char *IP = "192.168.15.2";
struct DAT//数据块,存放账户密码
{
char acc[30];
char pwd[20];
};
typedef struct DAT date;
struct client
{
date dat;
struct client *next;
};
typedef struct sockaddr AD;//类型定义
typedef struct client CLI;
CLI *head = NULL;//链表头
CLI *pnew = NULL;//指向下一个链表
CLI *tmp = NULL;//临时指针
int create_head(void);//创建链表头
void Init(void);//初始化TCP
void err(const char *buf,int line);//错误信息打印并退出
void Service(void);//等待客户函数
void *service_thread(void* p);//客户端服务函数
float enquiry(int fd,char *acc_buf,MYSQL sql,int flag);//查询余额
void save(int fd,char *acc_buf,MYSQL sql);//存钱
void withdraw(int fd,char *acc_buf,MYSQL sql);//取钱
void modpw(int fd,char *acc_buf,MYSQL sql);//改密
void trans(int fd,char *acc_buf,MYSQL sql);//转账
void logout(char *buf,MYSQL sql);//注销
int main(void)
{
create_head();
Init();
Service();
return 0;
}
void Service(void)
{
while(1)
{
struct sockaddr_in fromaddr;
int len = sizeof(fromaddr);
int fd ;
acc:
fd = accept(sockfd,(AD*)&fromaddr,&len);
if(fd == -1)
{ //err("accept",__LINE__);
printf("CONNECT ERROR!\n");
goto acc;
}
pthread_t id;
pthread_create(&id,0,service_thread,&fd);//有一个客户端即将建立连接时分配一个线程
tmp = head->next;
}
}
void *service_thread(void* p)
{
int fd = *(int *)p;
int option;
char acc_buf[30],pwd_buf[20],dat_buf[30];
MYSQL my_sql;
//初始化结构体
mysql_init(&my_sql);
//连接mysql数据库band_msg
if(mysql_real_connect(&my_sql,"localhost","root","1","band_msg",0,NULL,0)==NULL)
{
perror("mysql_real_connect");
return (void *)-1;
}
err: memset(acc_buf,0,sizeof(acc_buf));
text_fd = recv(fd,acc_buf,sizeof(acc_buf),0);
if(text_fd == -1)
err("recv",__LINE__);
memset(pwd_buf,0,sizeof(pwd_buf));
text_fd = recv(fd,pwd_buf,sizeof(pwd_buf),0);
if(text_fd == -1)
err("recv",__LINE__);
tmp = head->next;
while(tmp != NULL)//若链表中能够找到该帐号
{
if (strcmp(acc_buf,tmp->dat.acc) == 0)
{
if(strcmp(pwd_buf,tmp->dat.pwd) == 0)
{
char *cor_buf = "correct";
text_fd = send(fd,cor_buf,strlen(cor_buf),0);
goto cor;//帐号密码输入正确
}
else
{
char *err_buf = "error";
text_fd = send(fd,err_buf,strlen(err_buf),0);
goto err;
}
}
tmp = tmp -> next;
}
char *cor_buf = "correct";
text_fd = send(fd,cor_buf,strlen(cor_buf),0);
//没有找到,自动注册,在链表尾新建一个链表
pnew = (CLI *)malloc(sizeof(CLI));
pnew->next = NULL;
strcpy(pnew->dat.acc,acc_buf);
strcpy(pnew->dat.pwd,pwd_buf);
tmp=head;//确保加在了链表尾
while(tmp->next!=NULL)
{
tmp=tmp->next;
}
tmp->next = pnew;
//为该客户创建数据表(time change balance)
//为新用户创建表
char cli_buf[200];
memset(cli_buf,0,sizeof(cli_buf));
sprintf(cli_buf,"create table %s(time int(8),exchange decimal(10,2),balance decimal(12,2))",acc_buf);
//这里尽量不要用float因为float会出现一些小数计算失误,虽然我并没有用数据库的计算,时间为time函数得出来的数值,也可以改变为varchar型,
//然后用asctime函数得到时间字符串
//这里的exchange设置的(10,2),也代表了一次交易最大99999999.99,需要该上限的话可以改一下,后面的余额也一样
if((mysql_real_query(&my_sql,cli_buf,strlen(cli_buf)))!=0)
{
perror("mysql_real_query");
return (void *)-1;
}
//给新用户余额赋值为0
sprintf(cli_buf,"insert into %s(time,exchange,balance)values(%ld,0,0)",acc_buf,time(NULL));
if((mysql_real_query(&my_sql,cli_buf,strlen(cli_buf)))!=0)
{
perror("mysql_real_query");
return (void *)-1;
}
cor:
option = 0;
while(1)
{
MYSQL my_sql;
//初始化结构体
mysql_init(&my_sql);
//连接mysql数据库band_mes
if(mysql_real_connect(&my_sql,"localhost","root","xxxxx","band_msg",0,NULL,0)==NULL)//链接数据库
{
perror("mysql_real_connect");
return (void *)-1;
}
text_fd = recv(fd,dat_buf,sizeof(dat_buf),0);
if(text_fd == -1)
err("recv",__LINE__);
option = atoi(dat_buf);//将接收到的命令转换为整型,因为传来的是字符串
//0查询 1存款 2取款 3转账 4改密 5销户 6退出
switch(option)
{
case 0:enquiry(fd,acc_buf,my_sql,1);break;
case 1:save(fd,acc_buf,my_sql);break;
case 2:withdraw(fd,acc_buf,my_sql);break;
case 3:trans(fd,acc_buf,my_sql);break;
case 4:modpw(fd,acc_buf,my_sql);break;
case 5:logout(acc_buf,my_sql);break;
case 6:mysql_close(&my_sql);pthread_exit((void *)1);
}
}
}
float enquiry(int fd,char *acc_buf,MYSQL sql,int flag)//flag为标志位,表示给不给客户端发送余额,如果发送接收对应不齐会出现bug
{
//查询余额并发送
//select balance from tablename order by time desc limit 1选取最新一次的数据的余额
char buf[100],money[100];
memset(buf,0,sizeof(buf));
memset(money,0,sizeof(money));
sprintf(buf,"select balance from %s order by time desc limit 1",acc_buf);//这里获得的结果集就是最后一次的交易余额,只有一行一列
if((mysql_real_query(&sql,buf,strlen(buf))) != 0)
err("mysql_real_query",__LINE__);
MYSQL_RES *p=NULL;//获取到的数据库结果存放在了该结构体中
p = mysql_store_result(&sql);
if(p == NULL)
err("mysql_store_result",__LINE__);
int col = mysql_num_fields(p);
int row = mysql_num_rows(p);
MYSQL_ROW dat;
unsigned int i;
while((dat = mysql_fetch_row(p)))//在MySQL官网找的程序,可以循环得到结果集,我只选取了一行一列
{
unsigned long *lengths;
lengths = mysql_fetch_lengths(p);
for(i = 0;i< col;i++)
{
sprintf(money,"%.*s",(int)lengths[i],dat[i]?dat[i]:"NULL");
if(flag == 1)
text_fd = send(fd,money,strlen(money),0);
return atof(money);
}
}
mysql_free_result(p);//使用完结果集之后必须释放掉其内存空间
return -1;
}
void save(int fd,char *acc_buf,MYSQL sql)
{
//接收存钱的数目
//发送成功或者失败
char buf[100],money[100];
float saving,balance;
memset(buf,0,sizeof(buf));
memset(money,0,sizeof(money));
balance = enquiry(fd,acc_buf,sql,0);
text_fd = recv(fd,money,sizeof(money),0);
if(text_fd == -1)
err("recv",__LINE__);
saving = atof(money);//字符型转换为浮点型
sprintf(buf,"insert into %s(time,exchange,balance)values(%ld,%f,%f)",acc_buf,time(NULL),saving,balance+saving);
if((mysql_real_query(&sql,buf,strlen(buf)))!=0)
{
perror("mysql_real_query");
return ;
}
text_fd = send(fd,"correct",strlen("correct"),0);
return ;
}
void withdraw(int fd,char *acc_buf,MYSQL sql)
{
//接收取款的数目
//发送成功或者失败
char buf[100],money[100];
float wd,balance;
memset(buf,0,sizeof(buf));
memset(money,0,sizeof(money));
balance = enquiry(fd,acc_buf,sql,0);
text_fd = recv(fd,money,sizeof(money),0);
if(text_fd == -1)
err("recv",__LINE__);
wd = atof(money);
if(balance < wd)
{text_fd = send(fd,"error",strlen("error"),0);return;}
sprintf(buf,"insert into %s(time,exchange,balance)values(%ld,%f,%f)",acc_buf,time(NULL),wd,balance-wd);
if((mysql_real_query(&sql,buf,strlen(buf)))!=0)
{
perror("mysql_real_query");
return ;
}
text_fd = send(fd,"correct",strlen("correct"),0);
}
void trans(int fd,char *acc_buf,MYSQL sql)
{
//接受名字
//发送是否存在
//接受数目
//发送是否成功
int exist=0;
float tran,balance1,balance2;
char name[20],money[100],dat_buf[130];
err: memset(name,0,sizeof(name));
memset(money,0,sizeof(money));
memset(dat_buf,0,sizeof(dat_buf));
text_fd = recv(fd,name,sizeof(name),0);
if(text_fd == -1)
err("recv",__LINE__);
if(strcmp(name,"quit") == 0)
return;
tmp = head->next;
while(tmp != NULL)//若链表中能够找到该帐号
{
if (strcmp(name,tmp->dat.acc) == 0)
exist = 1;
tmp = tmp -> next;
}
if(exist == 0)
{text_fd = send(fd,"error",strlen("error"),0);goto err;}
else
text_fd = send(fd,"correct",strlen("correct"),0);
text_fd = recv(fd,money,sizeof(money),0);
if(text_fd == -1)
err("recv",__LINE__);
tran = atof(money);
balance1 = enquiry(fd,name,sql,0);//得到两人余额并进行计算
balance2 = enquiry(fd,acc_buf,sql,0);
sprintf(dat_buf,"insert into %s(time,exchange,balance)values(%ld,%f,%f)",name,time(NULL),tran,balance1+tran);
if((mysql_real_query(&sql,dat_buf,strlen(dat_buf)))!=0)
{
perror("mysql_real_query");
return ;
}
memset(dat_buf,0,sizeof(dat_buf));
sprintf(dat_buf,"insert into %s(time,exchange,balance)values(%ld,%f,%f)",acc_buf,time(NULL),tran,balance2-tran);
if((mysql_real_query(&sql,dat_buf,strlen(dat_buf)))!=0)
{
perror("mysql_real_query");
return ;
}
text_fd = send(fd,"correct",strlen("correct"),0);
}
void modpw(int fd,char *acc_buf,MYSQL sql)
{
//接受密码
//发送是否成功
char pw[100];
memset(pw,0,sizeof(pw));
text_fd = recv(fd,pw,sizeof(pw),0);
if(text_fd == -1)
err("recv",__LINE__);
tmp = head->next;
while(tmp != NULL)//若链表中能够找到该帐号
{
if (strcmp(acc_buf,tmp->dat.acc) == 0)
{
strcpy(tmp->dat.pwd,pw);
}
tmp = tmp -> next;
}
text_fd = send(fd,"correct",strlen("correct"),0);
}
void logout(char *buf,MYSQL sql)
{
CLI * tmp1 = NULL;
CLI * tmp2 = NULL;
tmp2=head;
tmp1=head->next;
while(tmp1 != NULL)//找到该帐号
{
if (strcmp(buf,tmp1->dat.acc) == 0)
{
tmp2->next = tmp1->next;
free(tmp1);
return ;
}
tmp2 = tmp2->next;
tmp1 = tmp1->next;
}
char drop_buf[150];
sprintf(drop_buf,"drop table %s",buf);//删除其数据库
if((mysql_real_query(&sql,drop_buf,strlen(drop_buf)))!=0)
{
perror("mysql_real_query");
return ;
}
}
int create_head(void)
{
head = (CLI *)malloc(sizeof(CLI));
if(head == NULL)
err("CREATE FAILURE!",__LINE__);
else
head->next = NULL;
return 1;
}
//TCP协议前面的步骤初始化
void Init(void)
{
sockfd = socket(PF_INET,SOCK_STREAM,0);//IPV4
if(sockfd == -1)
err("socket",__LINE__);
struct sockaddr_in addr;
addr.sin_family = PF_INET;
addr.sin_port = htons(PORT);//端口号
addr.sin_addr.s_addr = inet_addr(IP);//服务器为本机
if(bind(sockfd,(AD *)&addr,sizeof(addr)) == -1)
err("bind",__LINE__);
if(listen(sockfd,MAX_CLI) == -1)
err("listen",__LINE__);
printf("服务器初始化成功\n");
}
void err(const char *buf,int line)
{
fprintf(stderr,"出错行号是%d\n",line);
perror(buf);
exit(-1);
}
v1:
@gcc service.c -o s -lpthread -lmysqlclient
@gcc client.c -o c -lpthread -lmysqlclient
clean:
@rm s c a.out -rf
gedit:
@gedit service.c client.c
我写的简易聊天室和银行管理系统使用了许多相同的函数,因为之前写过比较方便嘛,思路也大体一致,只不过银行管理系统的功能更加完备一些,使用到的知识也相对多一些。