网络版ATM项目的实现——客户端

网络版的ATM实现思路

客户端

  1 #include "customer.h"
  2 
  3 static int sockfd;
  4 
  5 /*int create_msg_queue_c(int key)
  6 {
  7     //创建消息队列
  8     int msgid = msgget(key,IPC_CREAT|0644);
  9     if(0 > msgid)
 10     {
 11         perror("msgget");
 12         return -1;
 13     }
 14     return msgid;
 15 }*/
 16 
 17 void show_menu(void)
 18 {
 19     printf("Welcome to Online Bank !\n");
 20     printf("---------------------\n");
 21     printf("    [1]开户        \n");
 22     printf("    [2]登录        \n");
 23     printf("    [3]解锁        \n");
 24     printf("    [4]销户        \n");
 25     printf("    [5]退出        \n");
 26     printf("---------------------\n");
 27 }
 28 //开户界面
 29 void open_menu(void)
 30 {
 31     
 32     Msg msg = {99};
 33     //得到基本信息
 34     printf("请输入姓名:");
 35     gets(msg.acc.name);
 36     printf("请输入身份证号:");
 37     gets(msg.acc.idcard);
 38     printf("请输入预存金额:");
 39     scanf("%f",&msg.acc.money);
 40     //清空缓冲区
 41     stdin->_IO_read_ptr = stdin->_IO_read_end;
 42     strcpy(msg.acc.password,"123456");
 43     printf("%d\n",msg.acc.account);
 44     //将获得的基本信息发送到服务端
 45     send(sockfd,&msg,sizeof(Msg),0);
 46     //接收服务端传回的信息(账号id)
 47     recv(sockfd,&msg,sizeof(Msg),0);
 48     //perror("msgrcv");
 49     printf("*****您的id是%d,初始密码为123456,账号内的余额为%f*****\n",msg.acc.account,msg.acc.money);
 50     sleep(2);
 51 }
 52 //显示登陆后的功能界面
 53 void func_menu(void)
 54 {
 55     printf("Welcome to Online Bank !\n");
 56     printf("---------------------\n");
 57     printf("    [1]存款        \n");
 58     printf("    [2]取款        \n");
 59     printf("    [3]转账        \n");
 60     printf("    [4]查询        \n");
 61     printf("    [5]修密        \n");
 62     printf("    [6]退出        \n");
 63     printf("---------------------\n");
 64 }
 65 //退出登录
 66 void logout(int id)
 67 {
 68     
 69     Msg msg = {50};
 70     msg.acc.account = id;
 71     send(sockfd,&msg,sizeof(Msg),0);
 72     //接收服务端传回的信息(账号id)
 73     recv(sockfd,&msg,sizeof(Msg),0);
 74     printf("退出成功!\n");
 75     sleep(2);
 76 }
 77 //存钱界面
 78 void save(int id)
 79 {
 80     Msg msg = {5};
 81     msg.acc.account = id;
 82     printf("请输入要存的金额:");
 83     scanf("%f",&msg.acc.money);
 84     //清空缓冲区
 85     stdin->_IO_read_ptr = stdin->_IO_read_end;
 86     //将获得的基本信息发送到服务端
 87     send(sockfd,&msg,sizeof(Msg),0);
 88     //接收服务端传回的信息(账号id)
 89     recv(sockfd,&msg,sizeof(Msg),0);
 90     printf("存款成功!\n");
 91     printf("*****您的id是%d,账号内的余额为%f*****\n",msg.acc.account,msg.acc.money);
 92     sleep(2);
 93 }
 94 //取款界面
 95 void take(int id)
 96 {
 97     Msg msg = {6};
 98     msg.acc.account = id;
 99     printf("请输入要取的金额:");
100     scanf("%f",&msg.acc.money);
101     //清空缓冲区
102     stdin->_IO_read_ptr = stdin->_IO_read_end;
103     //将获得的基本信息发送到服务端
104     send(sockfd,&msg,sizeof(Msg),0);
105     //接收服务端传回的信息(账号id)
106     recv(sockfd,&msg,sizeof(Msg),0);
107     if(-1 == msg.acc.flag)
108     {
109         printf("取款失败!\n");
110         sleep(2);
111     }
112     else
113     {
114         printf("取款成功!\n");
115         printf("*****您的id是%d,账号内的余额为%f*****\n",msg.acc.account,msg.acc.money);
116         sleep(2);
117     }
118 }
119 //转账界面
120 void trans(int id)
121 {
122     Msg msg1 = {7};
123     //Msg msg2 = {17};
124     msg1.acc.account = id;
125     printf("请输入转账对象的id:");
126     scanf("%d",&msg1.acc.target);
127     //清空缓冲区
128     stdin->_IO_read_ptr = stdin->_IO_read_end;
129     printf("请输入要转账的金额:");
130     scanf("%f",&msg1.acc.money);
131     //清空缓冲区
132     stdin->_IO_read_ptr = stdin->_IO_read_end;
133     //将获得的基本信息发送到服务端
134     send(sockfd,&msg1,sizeof(Msg),0);
135     //接收服务端传回的信息(账号id)
136     recv(sockfd,&msg1,sizeof(Msg),0);
137     switch(msg1.acc.flag)
138     {
139         case -1:printf("您的余额不足!\n");sleep(2);break;
140         case -2:printf("转账对象不存在!\n");sleep(2);break;
141         case 0:    printf("转账成功!\n");
142                 printf("*****您的id是%d,账号内的余额为%f*****\n",msg1.acc.account,msg1.acc.money);
143                 sleep(2);break;
144     }
145 }
146 
147 //查询界面
148 void show(int id)
149 {
150     system("clear");
151     Msg msg = {8};
152     msg.acc.account = id;
153     //将获得的基本信息发送到服务端
154     send(sockfd,&msg,sizeof(Msg),0);
155     //接收服务端传回的信息(账号id)
156     recv(sockfd,&msg,sizeof(Msg),0);
157     printf("%s用户您好!\n",msg.acc.name);
158     printf("账号ID:%d\n",msg.acc.account);
159     printf("身份证号:%s\n",msg.acc.idcard);
160     printf("账号余额:%f\n",msg.acc.money);
161     printf("*****按任意键返回*****\n");
162     getchar();    
163 }
164 
165 //修改密码界面
166 void change(int id)
167 {
168     Msg msg = {9};
169     msg.acc.account = id;
170     printf("请输入您的身份账号以用于验证用户信息:");
171     gets(msg.acc.idcard);
172     printf("请输入新密码(6位):");
173     put_pw(msg.acc.password);
174     if(6 != strlen(msg.acc.password))
175     {
176         printf("密码格式不符!\n");
177         sleep(2);
178         return;
179     }
180     else
181     {
182         //将获得的基本信息发送到服务端
183         send(sockfd,&msg,sizeof(Msg),0);
184         //接收服务端传回的信息(账号id)
185         recv(sockfd,&msg,sizeof(Msg),0);
186         if(-1 == msg.acc.flag)
187         {
188             printf("修改失败!\n");
189             sleep(2);
190         }
191         else
192         {
193             printf("修改成功!\n");
194             sleep(2);
195         }
196     }
197 }
198 
199 //副主界面
200 void ano_main(int id)
201 {
202     while(1)
203     {
204         system("clear");
205         func_menu();
206         switch(getch())
207         {
208             case 49:save(id);break;
209             case 50:take(id);break;
210             case 51:trans(id);break;
211             case 52:show(id);break;
212             case 53:change(id);break;
213             case 54:logout(id);return;
214         }
215     }
216 }
217 //加载界面
218 void loading(void)
219 {
220     //system("clear");
221     char buf[103] = {};
222     memset(buf, ' ', sizeof(buf));
223     buf[0] = '[';
224     buf[101] = ']';
225     buf[102] = '\0';
226     int i = 0;
227     char index[6] = "-\\|/\0";
228     while (i <= 99)
229     {
230         buf[i+1] = '>';
231         printf("%s[%d%%][%c]\r",buf,i,index[i%4]);
232         fflush(stdout);//刷新缓冲区
233         usleep(50000);
234         i++;
235     }
236  
237     printf("\n");
238 }
239 //登录界面
240 void login_menu(void)
241 {
242     Msg msg = {2};
243     msg.acc.flag = -1;
244     //获取账号密码
245     printf("请输入账号:");
246     scanf("%d",&msg.acc.account);
247     //清空缓冲区
248     stdin->_IO_read_ptr = stdin->_IO_read_end;
249     printf("请输入密码:");
250     put_pw(msg.acc.password);
251     //将获得的基本信息发送到服务端
252     send(sockfd,&msg,sizeof(Msg),0);
253     //接收服务端传回的信息(账号id)
254     recv(sockfd,&msg,sizeof(Msg),0);
255     printf("%d\n",msg.acc.flag);
256     //根据判断结果跳转界面
257     if(0 == msg.acc.flag)
258     {
259         if(0 == msg.acc.sp)
260         {
261             loading();
262             ano_main(msg.acc.account);
263         }
264         else
265         {
266             printf("该账号已在其他客户端登录!\n");
267             sleep(2);
268             return;
269         }
270     }
271     else if(3 <= msg.acc.flag)
272     {
273         printf("账号已被锁定!请先前往解锁!\n");
274         sleep(2);
275         return;
276     }
277     else
278     {
279         printf("登录失败!用户或密码错误!\n");
280         sleep(2);
281         return;
282     }    
283 }
284 
285 //解锁界面
286 void unlock_menu(void)
287 {
288     Msg msg = {3};
289     printf("请输入要解锁的账号:");
290     scanf("%d",&msg.acc.account);
291     //清空缓冲区
292     stdin->_IO_read_ptr = stdin->_IO_read_end;
293     printf("请输入身份证号:");
294     gets(msg.acc.idcard);
295     printf("请输入新密码:");
296     put_pw(msg.acc.password);
297     //将获得的基本信息发送到服务端
298     send(sockfd,&msg,sizeof(Msg),0);
299     //接收服务端传回的信息(账号id)
300     recv(sockfd,&msg,sizeof(Msg),0);
301     if(-1 == msg.acc.flag)
302     {    
303         printf("输入信息不正确或该账户不需要解锁!\n");
304         sleep(2);
305         return;
306     }
307     printf("解锁成功!\n");
308     printf("*****您的id是%d,新密码为%s*****\n",msg.acc.account,msg.acc.password);
309     sleep(2);
310     return;    
311 }
312 
313 //销户界面
314 void delete_menu(void)
315 {
316     Msg msg = {4};
317     //获取账号密码
318     printf("请输入账号:");
319     scanf("%d",&msg.acc.account);
320     //清空缓冲区
321     stdin->_IO_read_ptr = stdin->_IO_read_end;
322     printf("请输入密码:");
323     put_pw(msg.acc.password);
324     //将获得的基本信息发送到服务端
325     send(sockfd,&msg,sizeof(Msg),0);
326     //接收服务端传回的信息(账号id)
327     recv(sockfd,&msg,sizeof(Msg),0);
328     if(-2 == msg.acc.flag)
329     {
330         printf("销户成功!\n");
331         sleep(2);
332     }
333     else
334     {
335         printf("销户失败!\n");
336         sleep(2);
337     }
338     return;
339 }
340 int main()
341 {
342     // 创建socket对象
343     sockfd = socket(AF_INET,SOCK_STREAM,0);
344     if(0 > sockfd)
345     {
346         perror("socket");
347         return -1;
348     }
349     // 准备通信地址
350     struct sockaddr_in addr = {};
351     addr.sin_family = AF_INET;
352     addr.sin_port = htons(1904);
353     addr.sin_addr.s_addr = inet_addr("192.168.1.110");
354     // 连接
355     if(0 > connect(sockfd,(struct sockaddr*)&addr,sizeof(addr)))
356     {
357         perror("connect");
358         return -1;
359     }
360     
361     while(1)
362     {
363         system("clear");
364         show_menu();
365         switch(getch())
366         {
367             case 49:open_menu();break;
368             case 50:login_menu();break;
369             //case 51:unlock_menu();break;
370             //case 52:delete_menu();break;
371             case 53:return 0;
372         }
373     }
374 }

使用的工具函数

 1 #include "customer.h"
 2 
 3 //创建消息队列
 4 int create_msg_queue(int keynum)
 5 {
 6     //获取ipc键值
 7     key_t key = ftok("~",keynum);
 8     //创建消息队列
 9     int msgid = msgget(key,IPC_CREAT|0644);
10     if(0 > msgid)
11     {
12         perror("msgget");
13         return -1;
14     }
15     
16     return msgid;
17 }
18 
19 //隐藏密码输入
20 char* put_pw(char* pw)
21 {
22     for(int i=0; i<20; i++)
23     {
24         stdin->_IO_read_ptr=stdin->_IO_read_end;
25         pw[i]=getch();
26         if(pw[i] == 127)
27         {
28             if(i>0)
29             {
30                 i -= 2;
31                 printf("\b \b");
32             }
33             else
34             {
35                 i--;
36             }
37         }
38         else if(pw[i] == 10)
39         {
40             pw[i]='\0';
41             break;
42         }
43         else
44         {
45             putchar('*');
46         }
47     }
48     return pw;
49 }

定义的头文件

 1 #ifndef CUSTOMER_H
 2 #define CUSTOMER_H
 3 
 4 #include <stdio.h>
 5 #include <sys/types.h>
 6 #include <sys/ipc.h>
 7 #include <sys/msg.h>
 8 #include <string.h>
 9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <fcntl.h>
12 #include <sys/wait.h>
13 #include <getch.h>
14 #include <stdbool.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
18 #include <pthread.h>
19 #include <semaphore.h>
20 #include <signal.h>
21 
22 #define key1 123456
23 #define key2 654321
24 typedef struct Account
25 {
26     int account;
27     int target;
28     char name[20];
29     char password[10];
30     char idcard[18];
31     float money;
32     int flag;
33     int sp;
34 }Account;
35 typedef struct Msg
36 {
37     long type;
38     Account acc;
39 }Msg;
40 
41 int create_msg_queue(int keynum);
42 char* put_pw(char* pw);
43 
44 #endif

Makefile

 1 all: 2 gcc -std=gnu99 -c customer.c 3 gcc -std=gnu99 -c tools.c 4 gcc customer.o tools.o -o customer -lpthread 

转载于:https://www.cnblogs.com/kid971220/p/10497801.html

Bank Account Management System 银行账户管理子系统 简称BAMS 这是一个基于C/S结构的银行账户在线管理系统,用户可以通过ATM终端界面来操作自己的银行账户. ATM 1: 要求1:封装一个Account类 - 业务数据 写一个账户类(Account),属性并且完全封装(注意:要辨别每个属性的set/get方法是否需要公开): id:账户号码 长整数(Long) password:账户密码 字符串类型(String) name:真实姓名 字符串类型(String) personId:身份证号码 字符串类型(String) email:客户的电子邮箱 字符串类型(String) balance:账户余额 双精度(double) 方法: deposit: 存款方法,参数类型:double, 返回类型:Account withdraw:取款方法,参数类型:double, 返回类型:Account 构造方法: 有参和无参,有参构造方法用于设置必要的属性 ATM 2:要求1:完成以下两种账户类型的编码。 银行的客户分为两大类:储蓄账户(SavingAccount)和信用账户(CreditAccount),两种的账户类型的区别在于: 储蓄账户不允许透支,而信用账户可以透支,并在用户在满足银行条件的情况下允许用户调整自己的透支额度. 注意: 1、CreditAccount需要多一个属性 ceiling 透支额度; 2、CreditAccount需要覆盖(重写)Account中的取款方式withdraw()。 要求2:完成Bank类的编码。 属性: 1.当前所有的账户对象的信息,存放在数组中: Account[]. 2.当前账户数量index. 方法: 1. 用户开户(register) 参数列表: Long 账号, String密码, String确认密码,String 姓名,String身份证号码,String邮箱,int 账户类型; (Long id, String password, String repassword, String name, String personID, String email, int type) 返回类型:Account 项目需求规定账户类型:0 – 储蓄账户 1 – 信用账户 2 – 可贷款储蓄账户 3– 可贷款信用账户 2. 用户登录(login) 参数列表: Long 账号, String密码; (Long id, String password) 返回类型:Account 3. 用户存款(deposit) 参数列表: Long 账号, double存款金额; (Long id, double money) 返回类型:Account 4. 用户取款(withdraw) 参数列表: Long 账号,String 密码,double取款金额; (Long id, String password, double money) 返回类型:Account 5. 设置透支额度(updateCeiling) 参数列表: Long 账号, String 密码,double透支额度金额; (Long id, String password, double money) 返回类型:Account 提示:这个方法需要验证账户是否是信用账户 6. 转账功能(transfer) 参数:from转出账户,passwordFrom 转出账号的密码,to转入账户,money转账的金额 (Long from, String passwordFrom, Long to, double money) 返回值:boolean 要求3:另外,请为Bank类添加几个统计方法 1.统计银行所有账户余额总数 2.统计所有信用账户透支额度总数 要求4:编写测试类 写个测试类,测试以上代码能否正常工作。 要求5:覆盖toString方法 查看对象的内容。 ATM 3: 要求1:让银行来提供账号(id)的生成 修改Account类和Bank类,银行用户的账号(id)应是自动生成的,初始值为: 862150212013020001(国家+邮编+年+月+序号)。 比如:第一个开户的账号为862150212013020001,第二开户的账号为862150212013020002 … 依此类推. 要求2:修改存款和取款方法 对于Account类中的存款方法和取款方法进行修改. 存款方法:改为不允许子类修改 取款方法:改为抽象方法,便于在子类中去覆盖(重写) 要求3:单例 将Bank类作成单例。 提醒:一定要理解使用单例模式的原理。 ATM 4: 要求1:新增一个贷款功能 为了满足业务发展的需求,银行需要为用户提供贷款的功能,来满足更多的用户需求。 抽象出一个贷款功能的接口:Loanable 该接口具有以下功能: a) 贷款(requestLoan) 参数:money贷款金额 返回类型:Account b) 还贷(payLoan) 参数:money还贷款金额 返回类型:Account 提醒:一定要理解抽象接口的原理和真实含义。 要求2:新增两种的新的账户类型 为了满足业务发展的需求,新增两种具有贷款功能的账户类型:可以贷款不可以透支账户和可以贷款可以透支账户; 为SavingAccount和CreditAccount各自添加一个子类LoanSavingAccount类和LoanCreditAccount类,同时让两个新增的子类都必须要实现Loanable接口。为了表示某个贷款账户的贷款金额,需要为所有的可贷款账户提供一个能记录贷款金额,所以要为CreditAccount类整一个普通的成员属性loanAmount,为长整形(long)。 说明1:LoanSavingAccount类表示该账户可以贷款,不可以透支; LoanCreditAccount类表示该账户可以贷款,可以透支。 说明2:贷款和透支是不一样的,透支指的是账户余额小于0,而贷款用户需要一个贷款额的属性. 在ATM机上,用户可以选择贷款,也可以选择还贷款,而还贷款就是要把账户余额上的资金转到贷款额上 例如: 用户余额10000元,贷款额100000元,用户可以选择还款5000元,则用户余额变为5000,贷款额变为95000元. 要求3:为Bank类添加三个新方法 a) 贷 款(requestLoan) 参数:id 账户,money贷款金额 (Long id , double money) 返回类型:Account b) 还贷款(requestLoan) 参数:id 账户,money还贷款金额 (Long id , double money) 返回类型:Account c) 统计所有账户贷款的总额(totoal) 参数:无 返回类型:double ATM 5: 要求1: 修写Bank类,采用集合的方式来管理多个Account对象 注意:通过分析每种集合的具体功能和特性后,选择合适的集合类型实现该功能。 要求2: 为Bank类添加一个方法,能够打印所有用户的总资产排名(提高部分) 说明: 1)、一个用户可能会有多个账号,以身份证号为准. 2)、总资产指多个账户余额的总和,不需要考虑贷款账户的贷 ATM 6:Exception 要求1: 为ATM增加业务异常类: ATMException: ATM业务异常基类。 BalanceNotEnoughException :用于取钱的时候余额不足的情况(包括账户余额超过透支额的情况) RegisterException:用于开户异常的情况,例如密码两次输入不一致等情况 LoginException:用户登录异常的情况,例如id错误,密码错误 LoanException:贷款额不能为负数,如果用户试图将贷款额置为负数,则会抛出这个异常 注意:在此异常的基础也可以继续扩展适合业务的异常类。 ATM 7:Swing GUI开发 第一步部分:为ATM项目添加用户客户端操作界面 需要以下几个类: 1) ATMClient: 其中会包含一个Frame,这是用户主界面. 2) MainPanel:主界面,用户可以选择开户或者登录 3) RegisterPanel:用户开户具体用到的界面 4) LoginPanel:用户登录需要的界面 5) BusinessPanel:界面上会显示账户的功能, 至少包括存款\取款\对于可透支的用户,允许用户修改透支额度\对于贷款用户,允许用户贷款和还贷款\转账。 第二步部分:为用户客户端操作界面添加事件处理 要求:在开户或者登录之后都会跳到BusinessPanel,而用户点击了交易之后,界面停留在BusinessPanel 要随时注意在BusinessPanel上根据数据的变化更新显示信息。 ATM 8:I/O&File 项目详细内容介绍 1、 分析: 将账户对象保存文件中,前期为新的账户对象分配id的做法(使用static特性)不再合适现今业务需求,也应相应的改变。 解决方案: 将下一个可用的id存放在文件中,每创建一个新对象的时候都会读取这个文件,获得新对象的id,并且修改文件中的id,使其加1后,再保存到文件中。 2、 修改Bank类中各个业务方法 分析: 要将账户信息全部保存到文件中,然后再从文件读取到内存中进行业务操作,而后再将处理完的业务对象重新保存到文件中永久保存起来。 解决方案: 1)采用对象序列化和反序列化技术。 2)将全部账户信息采用对象序列化的方式存放在文件中。 提示: 1) 使用文件来保存各种账户的信息,将注册、存款、取款、转账、修改之后的信息要及时的保存到文件中,时刻保证内存和文件中数据的一致性。 2) 采用何种存放方式,自由发挥决定。 ATM 9:NetWork 分析: 在现有的ATM中,用户是通过界面直接访问Bank对象,这种方式不符合业务需求,因为银行后台是受保护的绝对安全的业务操作,所以将其改为C/S结构,由界面充当客户端,通过TCP协议访问服务器端的核心业务对象(Bank对象). 解决方案: 1) 多线程技术 2) 网络编程技术 3) 需要完成服务端的编程,负责完成接收客户端的请求和相关业务处理。 注意:如何保证多个客户端同时登陆,并且保证业务数据在冲突的情况下,不能受到破坏。 提示:客户端和服务器端需要通过对象(TO)来传递信息,,这里会使用对象序列化技术.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值