功能描述:1:开户;2:销户;3:存钱;4:取钱;5:查询;6:转账;

主要用的技术:

  一:消息队列:

    1)key_t key = ftok(".",100); //获取key

    2)msgid = msgget(key,IPC_CREATE|0666); //创建   msgid = msgget(key,0); //获取

    3)msgsnd = msgsnd = (msgid,&msg,sizeof(msg),0);  //发送

    4)msgrcv = msgrcv = (msgid,&msg,sizeof(msg),0,0); //获取

    5)msgt = msgctl(msgid,IPC_RMID,NULL);  //删除

  二:信号:

      signal(int sinno, void (*fa)(int));

  三:文件操作:

      int access(const char *filename);  //查看文件是否存在

      int open(int fd,int oflag,.../* mode_t mode*/)

      ssize_t write(int fd,void *buf,size_t nbytes);

      ssize_t read(int fd,void *buf,size_t nbytes);

思想架构:

  头文件:

    dao.h   ----> 定义文件操作的函数

    bank.h  -----> 定义宏,结构体,设置外部变量 key1 key2

  .c文件

    client.c  ---->  客户端操作  主要包括客户端的输入提示,和把数据传入服务器端

    server.c  ---->  创建消息队列,启动服务端,用vfork()创建子进程,用execl() 执行open.c 的目标文件。并且设定  SIG_INT 信号,接收此信号时就删除消息队列。

    open.c  ----->  用来接收客户端传来的消息,并对消息进行业务逻辑操作

    dao.c   ----->   dao.h中一定的函数的具体实现,供open.c 文件调用,主要是用来对文件的操作。

    bank.c  ---->  此文件主要用来对两个 key 赋值。

感觉有点类似网站建设中的三层架构。

client.c  主要用来负责用户层

open.c  主要用来负责业务逻辑层

dao.c  主要用来负责数据操作层

 

设计的技术点不多,但是确实个规范的项目。头文件和各个文件的作用值得学习。框架是老师建的,功能都是自己实现的,如有错误还望指正:

bank.h:

 1 //客户端和服务器端共用的头文件
 2 #ifndef BANK_H_
 3 #define BANK_H_
 4 //声明两个key值,用来给消息队列用,这两个key在另一个文件中定义
 5 
 6 extern const int key1;//客户端向服务器发送消息队列的键值key
 7 extern const int key2;//服务器向客户端发送的
 8 
 9 //消息类型 定义为各种宏 方便处理
10 #define M_OPEN 1//代表开户类型
11 #define M_DESTROY 2 //销户
12 #define M_SAVE 3 //存钱
13 #define M_TAKE 4 //取钱
14 #define M_QUERY 5 //查询
15 #define M_TRANSF 6 //转账
16 #define M_SUCCESS 7 //处理成功
17 #define M_FAILED 8 //处理失败
18 
19 //包含帐户信息的帐户结构体
20 struct Account{
21     int id;//帐号
22     char name[10];//用户名
23     char password[10];//密码
24     double balance;//金额
25 };
26 
27 //消息的结构体
28 struct Msg{
29     long  mtype;//消息的类型
30     struct Account acc;//帐户的信息结构体
31 };
32 #endif

dao.h:

 1 //数据对象的存储
 2 #ifndef DAO_H_
 3 #define DAO_H_
 4 #include "bank.h"
 5 //生成不重复的帐号
 6 int generator_id();
 7 //将新帐号添加到文件中,为开户服务
 8 int createUser(struct Account acc);
 9 //销户功能
10 int destroyUser(struct Account acc);
11 //存钱功能
12 int saveMoney(struct Account acc,struct Account *p);
13 //取钱功能
14 int getMoney(struct Account acc,struct Account *p);
15 //查询余额功能
16 int checkMoney(struct Account acc,struct Account *p);
17 //转账功能
18 int moveMoney(struct Account acc1,struct Account acc2,struct Account *p);
19 #endif

bank.c:

1 //对头文件中的变量进行定义
2 #include "bank.h"
3 
4 const int key1 = 0x12345678;
5 const int key2 = 0x23456789;

server.c:

 1 //ATM的服务器端
 2 #include "bank.h"
 3 #include <sys/types.h>
 4 #include <sys/ipc.h>
 5 #include <sys/msg.h>
 6 #include <stdio.h>
 7 #include <stdlib.h>
 8 #include <unistd.h>
 9 #include <signal.h>
10 
11 //首先需要创建两个全局存储消息队列的id的变量
12 static int msgid1;
13 static int msgid2;
14 //写一个函数,用来创建两个消息队列,用到msgget函数
15 void init(){
16     //msgget函数,第一个参数是键值,bank.h中有
17     //IPC_CREAT表示没有此消息队列则创建,
18     //IPC_EXCL表示如果队列存在,则提示错误
19     //0666是给此消息队列对象添加一些权限设置,类似文件系统
20     //创建消息队列1
21     msgid1 = msgget(key1,IPC_CREAT|IPC_EXCL|0666);
22     if(msgid1 == -1){
23         perror("消息队列1创建失败"),exit(-1);
24     }
25     printf("消息队列1创建成功\n");
26     //创建消息队列2
27     msgid2 = msgget(key2,IPC_CREAT|IPC_EXCL|0666);
28     if(msgid2 == -1){
29         perror("消息队列2创建失败");
30         exit(-1);
31     }
32     printf("消息队列2创建成功\n");
33 }
34 //启动服务函数,用来创建子进程来执行用户不同的选择的结果
35 void start(){
36     printf("服务器正在启动..\n");
37     sleep(2);
38     //创建子进程
39     pid_t open_pid = vfork();
40     if(open_pid == -1){
41         perror("vfork failed");
42         exit(-1);
43     }
44     else if(open_pid == 0){//进入子进程
45         //printf("in child process\n");
46         execl("./open","open",NULL);//不再和父进程共用代码段
47         exit(-1);
48     }
49     else{
50         printf("正在等待客户端选择..\n");
51         waitpid(open_pid,0,0);//阻塞,等待子进程结束
52         //printf("in parent process\n");
53     }
54 }
55 
56 void sig_exit(){
57     printf("服务器正在关闭..\n");
58     sleep(1);
59     if(msgctl(msgid1,IPC_RMID,NULL) == -1){
60         perror("消息队列1删除失败\n");
61         exit(-1);
62     }
63     else{
64         printf("消息队列1删除成功\n");
65     }
66     if(msgctl(msgid2,IPC_RMID,NULL) == -1){
67         perror("消息队列2删除失败\n");
68         exit(-1);
69     }
70     else{
71         printf("消息队列2删除成功\n");
72     }
73     printf("服务器成功关闭\n");
74     exit(0);//直接结束程序
75     
76 }
77 int main(){
78     //我们退出服务器用一个信号处理函数来实现
79     printf("退出服务器请按CTRL+C\n");//发送SIGINT信号
80     signal(SIGINT,sig_exit);//自定义信号处理函数,进行退出操作
81     //做好了善后工作,我们从头开始启动服务器
82     //创建消息队列
83     init();
84     //启动服务
85     
86     start();
87     return 0;
88 }

open.c:

  1 /*开户*/
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <sys/types.h>
  5 #include <sys/ipc.h>
  6 #include <sys/msg.h>
  7 #include "bank.h"
  8 int main(){
  9     int msgid1 = msgget(key1,0);
 10     if(msgid1 == -1){
 11         perror("获取消息队列1失败");
 12         printf("服务器启动失败");
 13         exit(-1);
 14     }
 15     int msgid2 = msgget(key2,0);
 16     if(msgid2 == -1){
 17         perror("获取消息队列2失败");
 18         printf("服务器启动失败");
 19         exit(-1);
 20     }
 21     //获取到消息队列之后,开始接受消息
 22     while(1){
 23         struct Msg msg;//存储消息信息的结构体
 24         struct Account accMove,accResult;//存储帐户信息
 25         //首先从客户那里收取消息队列1的信息 msgrcv 函数
 26         if(msgrcv(msgid1,&msg,sizeof(msg.acc),0,0) <=0 ){
 27             break;
 28         }
 29         //如果接受到了消息,根据消息的不同类型进行不同的操作
 30         if(msg.mtype == M_OPEN){//如果类型是开户
 31             int id = generator_id();
 32             accMove = msg.acc;
 33             accMove.id = id;
 34             if(createUser(accMove)==-1){
 35                 printf("开户失败");
 36                 msg.mtype = M_FAILED;//将消息类型置成失败
 37             }
 38             else{
 39                 printf("开户成功");
 40                 msg.mtype = M_SUCCESS;
 41             }
 42             msg.acc.id = id;
 43             msgsnd(msgid2,&msg,sizeof(msg.acc),0);//将消息由消息队列2发送给客户端
 44             //执行开户的操作
 45             //给用户分配帐号,将用户信息记录在文件中。
 46         }
 47         //最后把消息发过去,这时候消息的类型应该是两种情况M_SUCESS
 48         //或者是M_FAILED 
 49         else if(msg.mtype == M_DESTROY){
 50             accMove = msg.acc;
 51             int desval = destroyUser(accMove);
 52             if(desval == -1){
 53                 printf("没有此ID\n");
 54                 msg.mtype = M_FAILED;
 55             }
 56             else if(desval == 0){
 57                 printf("销户失败!\n");
 58                 msg.mtype = M_FAILED;
 59             }
 60             else{
 61                 printf("销户成功!\n");
 62                 msg.mtype = M_SUCCESS;
 63             }
 64             if(msgsnd(msgid2,&msg,sizeof(msg.acc),0) == -1) perror("msgsnd"),exit(-1);
 65         }
 66         else if(msg.mtype == M_SAVE){
 67             accMove = msg.acc;
 68             int saval = saveMoney(accMove,&accResult);
 69             if(saval == -1){
 70                 printf("没有此ID\n");
 71                 msg.mtype = M_FAILED;
 72             }
 73             else if(saval == 0){
 74                 printf("存钱失败!\n");
 75                 msg.mtype = M_FAILED;
 76             }
 77             else{
 78                 printf("存钱成功!\n");
 79                 msg.mtype = M_SUCCESS;
 80             }
 81             msg.acc = accResult;
 82             if(msgsnd(msgid2,&msg,sizeof(msg.acc),0) == -1) perror("msgsnd"),exit(-1);
 83         }
 84         else if(msg.mtype == M_TAKE){
 85             accMove = msg.acc;
 86             int saval = getMoney(accMove,&accResult);
 87             if(saval == -1){
 88                 printf("没有此ID\n");
 89                 msg.mtype = M_FAILED;
 90             }
 91             else if(saval == 2){
 92                 printf("余额不足\n");
 93                 msg.mtype = M_FAILED;
 94             }
 95             else if(saval == 0){
 96                 printf("取钱失败!\n");
 97                 msg.mtype = M_FAILED;
 98             }
 99             else{
100                 printf("取钱成功!\n");
101                 msg.mtype = M_SUCCESS;
102             }
103             msg.acc = accResult;
104             if(msgsnd(msgid2,&msg,sizeof(msg.acc),0) == -1) perror("msgsnd"),exit(-1);
105             
106         }
107         else if(msg.mtype == M_QUERY){
108             accMove = msg.acc;
109             int saval = checkMoney(accMove,&accResult);
110             if(saval == -1){
111                 printf("没有此ID\n");
112                 msg.mtype = M_FAILED;
113             }
114             else if(saval == 0){
115                 printf("查询失败!\n");
116                 msg.mtype = M_FAILED;
117             }
118             else{
119                 printf("查询成功!\n");
120                 msg.mtype = M_SUCCESS;
121             }
122             msg.acc = accResult;
123             if(msgsnd(msgid2,&msg,sizeof(msg.acc),0) == -1) perror("msgsnd"),exit(-1);
124 
125         }
126         else if(msg.mtype == M_TRANSF){
127             struct Account accto;
128             accMove = msg.acc;
129             if(msgrcv(msgid1,&msg,sizeof(struct Account),0,0) == -1) perror("msgrcv"),exit(-1);
130             accto = msg.acc;
131             int tra = moveMoney(accMove,accto,&accResult);
132             if(tra == -1){
133                 printf("没有此ID\n");
134                 msg.mtype = M_FAILED;
135             }
136             else if(tra == 0){
137                 printf("转账失败\n");
138                 msg.mtype = M_FAILED;
139             }
140             else if(tra == 2){
141                 printf("余额不足\n");
142                 msg.mtype = M_FAILED;
143             }
144             else{
145                 printf("转账成功\n");
146                 msg.mtype = M_SUCCESS;
147             }
148             msg.acc = accResult;
149             if(msgsnd(msgid2,&msg,sizeof(struct Account),0) == -1) perror("msgsnd"),exit(-1);
150             
151         }
152     }
153     return 0;
154 }
View Code

相关文章: