方法网站目录,企业网站模板下载软件,呼市网站建设,郴州网站建设郴州文章分五部分#xff1a;需求分析、项目所需知识点、思路讲解、代码实现、功能演示 本文内容较长#xff0c;建议是按照我自己的思路给大家讲解的#xff0c;如果有其他问题#xff0c;欢迎评论区讨论 文章中的代码是在linux下编译实现的#xff0c;注意自己的环境。 需求分析、项目所需知识点、思路讲解、代码实现、功能演示 本文内容较长建议是按照我自己的思路给大家讲解的如果有其他问题欢迎评论区讨论 文章中的代码是在linux下编译实现的注意自己的环境。 一需求分析
我们的ATM终端要求实现下面的功能
1开户2存款3取款4查询5转账6退出7销户
二项目相关知识点
文件操作进程通信----消息队列模块编程数据库 上面的内容不再讲解根据代码可以查看相关函数的功能。
三思路讲解
1、实现功能用到进程间通信
1通信要求两个进程实现 两个进程分别完成什么任务站在用户的角度去考虑这个问题例如你去银行开户的场景你我要开户银行职员请出示你的相关信息你交出身份证 银行职员开始一系列的操作录入信息开账户等紧接着要求你输入密码你输入密码银行职员请确认密码你再次输入银行职员银行卡余额不能为空请存款你交出100元银行职员拿走你的钱在你的账户输入100........................从这个角度来讲你和银行职员就是两个不同的进程你们分别的任务有银行职员根据你的提示信息为你开户、存款、取款、查询、转账、退出、销户操作而你要做的就是给出相应的操作提示2进程间通信的选取
消息队列在进程通信比较有代表性我们在这里使用消息对列。2、进程任务分解
可以将进程分为客户端进程和服务端进程分别的任务有 服务端进程 1 首先用msgget函数创建两个消息队列消息队列1存放客户端进程发来的各种请求注意根据操作的不同会发送不同类型的消息可以自己定义消息的类型另外可以将功能函数作为一个模块这样会使得程序逻辑比较清晰消息队列2存放服务端进程回复给客户端进程的消息2利用fork函数创建进程父进程阻塞就行子进程通过exec函数来调用函数功能模块的可执行文件3捕获用户发来的Ctrlc的信号结束进程 并删除消息队列通过exit函数和msgctl功能函数实现模块功能编写1开户操作首先需要一个文件来保存用户的信息同时检测该文件是否已经存在---------------注意银行账号不能重复成功创建文件后将客户端进程发来的用户信息写入文件返回成功的消息类型给客户端2存款操作根据用户信息找到对应的文件将文件内的关于金额的值加上相应的取款金额3取款操作根据用户信息找到对应的文件将文件内的关于金额的值减去相应的取款金额4转账操作转账操作需要输入两个先关的用户信息之后就是取款操作和存款操作的结合5删除账户操作根据提示信息找到相对应的文件先要情况账户中的余额才能注销账户客户端进程
可以先写一个界面类似C语言的学员管理系统
根据界面的操作提示选择相对应的功能
操作有1开户2存款3取款4查询5转账6退出7销户
实现首先要获取消息队列1开户操作开户的时候榕湖需要输入用户的相关信息账户、密码、存款金额为了操作简便可以通过结构体来封装用户信息输入信息操作后将消息发送到消息队列并指定消息类型2存款向指定的账户存入指定的金额先输入用户相关信息将信息发送到消息队列并指定消息类型3取款先输入用户相关信息和取款金额将信息发送到消息队列并指定消息类型4查询先输入用户相关信息将信息发送到消息队列并指定消息类型5转账先输入当前用户相关信息和要转账到的用户信息将信息发送到消息队列并指定消息类型6转账先输入销毁用户信息将信息发送到消息队列并指定消息类型
以上操作只需要简单的录入信息和发送消息到消息队列如同你现在按取款机上对应的功能键具体操作在客户端调用的功能模块实现四代码实现
由于代码量比较大这里贴出客户端和服务端的代码其余的代码在链接资源里有需要的自行下载 client.c
/************************************************************************
*
* 文件名cLient.c
*
* 文件描述模拟银行终端客户端
*
* 创建人Liu ming 2020/2/13
*
* 版本号2.0
*
* 修改记录
*
************************************************************************/
#define DEBUG 1 //调试定义宏
#include stdio.h
#include signal.h
#include stdlib.h
#include string.h
#include msg_queue.h
//#define CLIENT 0
#ifdef CLIENT
int show_flag 0;//0--未登录界面 1--登录后界面
int sig_flag 0;//选择的功能id号
int msg_sendid 0,msg_recvid0;//消息队列id
struct signal signal_t {0,0}; //初始化进程通信信号/*
*
* 函 数 名Ctrl_c
*
* 参 数 任意整形
*
* 功能描述: 强制结束函数时删除消息队列
*
* 返 回 值无
*
* 作 者Liu ming 2020/2/13
*
*/
void Ctrl_c(int singal_num)
{system(pkill server);msgctl(msg_sendid,IPC_RMID,NULL);msgctl(msg_recvid,IPC_RMID,NULL);exit(0);
}/*
*
* 函 数 名is_ok
*
* 参 数 客户端请求码
*
* 功能描述: 如果用户输入1则请求码被传递到消息队列结构体并调用handle进行发送接收处理输入其他不做任何操作
*
* 返 回 值 0 ------输入了确认-1-------输入了取消
*
* 作 者Liu ming 2020/2/13
*
*/
int is_ok(int flag)
{int num0;//提示用户进行输入printf(输入 1 进行确认输入 2 退出操作: \n);scanf(%d,num);if(num !1){printf(请重新选择~\n);return -1;}sig_flag flag ;handle();//退出登录账号 清除结构体if(sig_flag 3 || sig_flag 1){InitMsg_t(signal_t,1);//销户后清除客户端信息}return 0;
}
/*
*
* 函 数 名handle
*
* 参 数 无
*
* 功能描述: 发送请求功能码接收服务端的数据处理返回的数据
*
* 返 回 值无
*
* 抛出异常
*
* 作 者Liu ming 2020/2/13
*
*/
void handle()
{signal_t.num sig_flag;//复制请求码到消息队列
#ifdef DEBUGprintf(send operation code : %d\n,signal_t.num);
#endifmsgsnd(msg_sendid,(const void *)signal_t,sizeof(signal_t)-4,0);//发送消息请求msgrcv(msg_recvid,(void *)signal_t,sizeof(signal_t)-4,0,0);//阻塞接收消息
#ifdef DEBUGprintf(receive operation code : %d\n,signal_t.num);
#endif//根据接收功能码处理不同的信息switch(signal_t.num){case 30://开户成功printf(姓名%s\n,signal_t.name);printf(身份证号%s\n,signal_t.identyCard);printf(手机号码%s\n,signal_t.phone);printf(分配的银行卡号:%d\n,signal_t.id);break;case 60://开户失败printf(请输入正确的身份信息\n);break;case 31://登录--账号密码正确show_flag 1;//进入登录界面break;case 61://登录--账号错误show_flag 0;//进入登录界面printf(账号或密码错误,请重试\n);break;case 62://登录--密码错误show_flag 0;//进入登录界面printf(账号或密码错误,请重试\n);break;case 32://销户--成功show_flag 0;//进入登录界面break;case 63://销户--失败printf(销户失败请重试\n);break;case 33://存款--成功show_flag 1;//printf(存款成功当前余额为%f\n,signal_t.money);break;case 64://存款--失败printf(存款失败请重试\n);break;case 34://取款--成功show_flag 1;//printf(取款成功取出%f\n,signal_t.money);break;case 65://取款--失败printf(取款失败请重试\n);break;case 35://转账--成功show_flag 1;//printf(转账成功转出%f\n,signal_t.money);break;case 66://余额不足printf(余额不足请重试\n);break;case 67://银行卡号不存在printf(银行卡号不存在请重试\n);break;case 36://余额查询--成功printf(余额%f\n,signal_t.money);break;case 68://余额查询--失败printf(销户失败请重试\n);break;default:printf(传输信息出错\n);break;}
}/*
*
* 函 数 名menu
*
* 参 数无
*
* 功能描述: 提供显示和选择功能并根据选择调用handle()函数
* 进行数据的发送接收处理
* 返 回 值无
*
* 作 者Liu ming 2020/2/13
*
*/
void menu()
{int num0;while(1){
#ifdef DEBUGprintf(showflag%d\t signalflag%d\n,show_flag,sig_flag);
#endifswitch(show_flag){case 0: //界面一 主界面printf(-------------------------------------------------------------\n);printf(| | \n);printf(| Welcome to bank system | \n);printf(| | \n);printf(| 1.登录 | \n);printf(| 2.开户 | \n);printf(|_____________________________________________________________| \n);printf(choose-);scanf(%d,num);switch(num){case 1:{show_flag 3;//进入登录页面}break;case 2:{show_flag 2;//进入开户界面}break;default :printf(请重新输入!\n);}break;case 1://界面二 登录进去后printf(-------------------------------------------------------------\n);printf(| | \n);printf(| Welcome to bank system | \n);printf(| | \n);printf(| 0.退出 | \n);printf(| 1.销户 | \n);printf(| 2.存款 | \n);printf(| 3.取款 | \n);printf(| 4.转账 | \n);printf(| 5.余额查询 | \n);printf(|_____________________________________________________________| \n);printf(choose-);scanf(%d,num);switch(num){case 0://退出show_flag 0;InitMsg_t(signal_t,1);//初始化结构体break;case 1://销户is_ok(3);//3为销户请求码break;case 2://存款printf(请输入存款金额);scanf(%f,signal_t.money);is_ok(4);//4为存款请求码break;case 3://取款printf(请输入取款金额);scanf(%f,signal_t.money);//发送取款请求码5is_ok(5);break;case 4://转账printf(请输入转账账号);scanf(%d,signal_t.tmpId);printf(请输入转账金额);scanf(%f,signal_t.money);is_ok(6);//6为转账请求码break;case 5://余额查询sig_flag 7;handle();break;default:printf(请重新输入!\n);}break;case 2://界面三 开户界面printf(-------------------------------------------------------------\n);printf( 正在进行开户操作... \n);printf(请输入姓名);scanf(%s,signal_t.name);printf(请输入身份证号);scanf(%s,signal_t.identyCard);printf(请输入手机号码);scanf(%s,signal_t.phone);printf(请输入密码);scanf(%s,signal_t.passwd);is_ok(1);//1为开户请求码show_flag 0;// if(! is_ok(1))sig_flag 0;break;case 3 : //界面四 登录界面printf(-------------------------------------------------------------\n);printf( Welcome to bank system \n);printf(请输入账号);scanf(%d,signal_t.id);printf(请输入密码);scanf(%s,signal_t.passwd);if(is_ok(2)){sig_flag 0;show_flag0;InitMsg_t(signal_t,1);//清除结构体}break;}}
}int main(int argc, char *argv[])
{signal(SIGINT,Ctrl_c);//强制退出时删除开辟的资源msg_sendid get_msg(123);//获得发送消息对列msg_recvid get_msg(456);//获得接收消息对列InitMsg_t(signal_t,1);//初始化消息类型1menu();return 0;
}
#endifserver.c
/************************************************************************
*
* 文件名cLient.c
*
* 文件描述模拟银行终端客户端
*
* 创建人Liu ming 2020/2/13
*
* 版本号2.0
*
*注释
---------------------------------------------------------------------------------------------------------
* 操作 客户端(client) 请求功能码 服务端(server) ** 开户 01 成功返回30 失败返回60* 登录 02 成功返回31 卡号错误61密码错误62* 销户 03 成功返回32 失败返回63* 存款 04 成功返回33 失败返回64* 取款 05 成功返回34 失败返回65* 转账 06 成功返回35 余额不足返回66 转账账号不存在67* 余额查询 07 成功返回36 失败返回68--------------------------------------------------------------------------------------------------------
* 修改记录
*
************************************************************************/
#include stdio.h
#include stdlib.h
#include signal.h
#include string.h
#include mysql.h
#include msg_queue.h#define DEBUG 1#ifdef SERVER
int num 000;//分配的卡号
int sig_flag 0;//选择功能id号
char sql_buf[1024];//sql语句存放数组
struct signal signal_t {0,0}; //进程通信信号
int msg_sendid0,msg_recvid0;//消息队列id
/*
*
* 函 数 名give_account
*
* 参 数无
*
* 功能描述: 查询数据库中最后一个id把id1作为新账户分配下去.
*
* 返 回 值成功卡号失败-1
*
* 抛出异常
*
* 作 者Liu ming 2020/2/13
*
*/
int give_account()
{memset(sql_buf,0,sizeof(sql_buf));//清除数组中的内容strcpy(sql_buf,select cast(id as unsigned integer) from bank order by date desc );errno mysql_real_query(pmysql,sql_buf,strlen(sql_buf));if(errno){printf(getid query error!\n);mysql_close(pmysql);exit(0);}res mysql_store_result(pmysql);if(res NULL){printf(没有获取到有效id\n);return -1;}row mysql_fetch_row(res);num 1 atoi(row[0]);//返回生成的号码return num;}/*
*
* 函 数 名Ctrl_c
*
* 参 数 任意整形
*
* 功能描述: 强制结束函数时删除消息队列
*
* 返 回 值无
*
* 作 者Liu ming 2020/2/13
*
*/
void Ctrl_c(int singal_num)
{system(pkill client);msgctl(msg_sendid,IPC_RMID,NULL);msgctl(msg_recvid,IPC_RMID,NULL);exit(0);
}/*
*
* 函 数 名query_money
*
* 参 数 id -- 银行卡卡号
*
* 功能描述: 根据输入的银行卡卡号查询余额
*
* 返 回 值返回查询的余额
*
* 作 者Liu ming 2020/2/13
*
*/
float query_money(int id)
{sprintf(sql_buf,select money from bank where id%d,id);errno mysql_real_query(pmysql,sql_buf,strlen(sql_buf));memset(sql_buf,0,sizeof(sql_buf));if(errno){printf(query money error!);signal_t.num 67;//余额查询失败return -1;}res mysql_store_result(pmysql);row mysql_fetch_row(res);return atoi(row[0]);
}/*
*
* 函 数 名insert_money
*
* 参 数 id -- 银行卡卡号money ---金额
*
* 功能描述: 根据输入的银行卡卡号修改用户余额
*
* 返 回 值成功返回0失败返回-1
*
* 作 者Liu ming 2020/2/13
*
*/
int insert_money(int id,float money)
{sprintf(sql_buf,update bank set money %f where id %d,money,id);errno mysql_real_query(pmysql,sql_buf,strlen(sql_buf));memset(sql_buf,0,sizeof(sql_buf));if(errno){printf(update money error!);return -1;}return 0;}
/*
*
* 函 数 名handle
*
* 参 数 无
*
* 功能描述: 处理客户端发来的功能请求
*
* 返 回 值无
*
* 作 者Liu ming 2020/2/13
*
*/
void handle(void)
{float tmp_money0;sig_flag signal_t.num;printf(接收操作码%d\n,sig_flag);switch(sig_flag){case 1://开户操作printf(---------------------------------\n);printf(姓名%s\n,signal_t.name);printf(身份证号%s\n,signal_t.identyCard);printf(手机号码%s\n,signal_t.phone);//生成卡号signal_t.id give_account();if(signal_t.id 0){perror(give_account()\n);return ;}printf(生成的id%d\n,signal_t.id);//存储信息到数据库memset(sql_buf,0,sizeof(sql_buf));sprintf(sql_buf,insert into bank values(%d,%s,%s,%s,%s,%s,now()),\signal_t.id,signal_t.name,1,signal_t.phone,signal_t.identyCard,signal_t.passwd);errno mysql_real_query(pmysql,sql_buf,strlen(sql_buf));#ifdef DEBUGprintf(%s\n,sql_buf);#endif // DEBUGif(errno){printf(insert card info error!);signal_t.num 60;//卡号输入错误}else{signal_t.num 30;//分配卡号正确}break;case 2://登录操作memset(sql_buf,0,sizeof(sql_buf));sprintf(sql_buf,select passwd from bank where id%d,signal_t.id);errno mysql_real_query(pmysql,sql_buf,strlen(sql_buf));if(errno){printf(query passwd error!);return;}res mysql_store_result(pmysql);row mysql_fetch_row(res);if(row 0){signal_t.num 61;//查询信息出错无此人}else{if(strcmp(row[0],signal_t.passwd)0){printf(账号密码正确\n);signal_t.num 31;//账号密码正确}else{signal_t.num 62;//密码错误printf(密码错误);}}break;case 3://销户//删除数据库制定的信息memset(sql_buf,0,sizeof(sql_buf));sprintf(sql_buf,delete from bank where id %d,signal_t.id);#ifdef DEBUGprintf(sql[]%s\n,sql_buf);#endif // DEBUGerrno mysql_real_query(pmysql,sql_buf,strlen(sql_buf));if(errno){printf(delete card info error!);signal_t.num 63;//删除信息出错}else{signal_t.num 32;//删除成功}break;case 4://存款//查询余额tmp_moneyquery_money(signal_t.id);//修改余额tmp_money signal_t.money;//存入数据库if(insert_money(signal_t.id,tmp_money)0){signal_t.money tmp_money;signal_t.num 33;}elsesignal_t.num64;break;case 5://取款//查询余额tmp_moneyquery_money(signal_t.id);//修改余额if(tmp_moneysignal_t.money){signal_t.money tmp_money;tmp_money0;}else{tmp_money - signal_t.money;}//存入数据库if(insert_money(signal_t.id,tmp_money)0){signal_t.num 34;}elsesignal_t.num65;break;case 6://转账sprintf(sql_buf,select money from bank where id%d,signal_t.tmpId);errno mysql_real_query(pmysql,sql_buf,strlen(sql_buf));memset(sql_buf,0,sizeof(sql_buf));if(errno){printf(query passwd error!);return;}res mysql_store_result(pmysql);row mysql_fetch_row(res);if(row 0){signal_t.num 67;// 银行卡卡号不存在}else{tmp_moneyquery_money(signal_t.id);//修改余额if(tmp_moneysignal_t.money){signal_t.num 66;//余额不足}else{signal_t.num 35;//余额不足tmp_money - signal_t.money;insert_money(signal_t.id,tmp_money);//扣除转账账户的余额tmp_moneyquery_money(signal_t.tmpId);tmp_money signal_t.money;insert_money(signal_t.tmpId,tmp_money);//增加被转账账户的余额}}break;case 7://查询余额tmp_moneyquery_money(signal_t.id);printf(your money : %f\n,tmp_money);signal_t.money tmp_money;signal_t.num 36;//余额查询成功break;default :break;}
}int main(int argc, char *argv[])
{signal(SIGINT,Ctrl_c);//强制退出时删除消息对列//连接数据库pmysql connect_mysql(test);//检测某表是否存在指定数据库中errno table_isExist(pmysql,bank);if(errno){// talbe is not exist,//create table in hear !char buf[]create table bank(id int not null auto_increment primary key , name varchar(20) not null, \money float default 0,phone varchar(11) not null,identyCard varchar(18) not null unique,\passwd varchar(20) not null,date DATETIME );//执行创建表格MySQL语句errno mysql_real_query(pmysql,buf,strlen(buf));//插入一条默认数据char test[]insert into bank values(1,admin,0,null,admin,666666,now());errno mysql_real_query(pmysql,test,strlen(test));//设置可以存储中文memset(sql_buf,0,sizeof(sql_buf));sprintf(sql_buf,alter table %s CONVERT TO CHARACTER SET utf8,bank);errno mysql_real_query(pmysql,sql_buf,strlen(sql_buf));#ifdef DEBUGprintf(the table is not exist ,creating success!\n);#endif // DEBUG}else{#ifdef DEBUGprintf(the table is exist \n);#endif // DEBUG}msg_recvid get_msg(123);//获得接收消息队列msg_sendid get_msg(456);//获得发送消息队列while(1){printf(----------------------------------------\n);printf(等待接受信息\n);msgrcv(msg_recvid,(void *)signal_t,sizeof(signal_t)-4,0,0);#ifdef DEBUGprintf(receive operation code : %d\nname%s\niddentCar%s\nphone%s\npasswd%s\nid%d\nmoney%f\n,signal_t.num,signal_t.name,signal_t.identyCard,signal_t.phone,signal_t.passwd,signal_t.id,signal_t.money);#endif // DEBUGhandle();//处理接收的信息printf(send operation code : %d\n,signal_t.num);msgsnd(msg_sendid,(const void *)signal_t,sizeof(signal_t)-4,0);//0队列满时阻塞}return 0;
}五功能演示
开户功能演示 存款功能演示 其他功能就不演示了感兴趣可以下载代码自己尝试。