linux 下多进程编程 银行小系统(进程间通信--消息队列)

项目要求

主要分为两人大模块:

客户端
	1、进入时的功能开户、销户、登录、解锁
		开户:输入姓名、身份证号、设置密码,如果开户成功,则服务器上保存一个账号信号(一个账号存一个文件,文件名建议是账号)。
		销户:输入帐号、密码,服务器询问是否确认销户,如果确认则服务器删除帐号文件,并记录帐号。
		登录:输入账号、密码,三次错误账号锁定。
		解锁:输入账号、身份证号解锁。
	2、登录成功:存钱、取钱、转账、查询、修改密码
		存钱:输入存钱金额
		取钱:输入取钱金额
		转账:目标帐号和要转的金额
		查询:不需要输入数据
		修改密码:原密码和新密码
服务器
	如果识别功能:根据消息的类型识别客户端请求的功能。
	开启服务各项功能的子进程
		各进程按照消息类型接收消息
	
头文件

#define key 123456

帐号结构体
{
	帐号
	身份证号
	密码
	金额
}

消息结构体
{
	消息类型
	帐号结构体
}

源码传送门:码云:传送门

思路:

封客户端(client)和服务端(server)两个端口,通过建立一条消息队列建立客户端与服务端之间的联系。在服务端中通过vfork函数建立9个子进程,一个子进程对应一个项目的功能要求,然后通过客户端送不同消息类型,对应子进程接收对应的消息类型,处理客户端需求。

部分代码展示

客户端代码

#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"

int msgid;
int init(void);			//初始化获取消息队列
Account online_user = {};		//登陆成功的在线用户

void menu(void);		//主界面
void open_act(void);		//开户
void destroy_act(void);		//销户
void login(void);		//登陆
void unlock(void);		//解锁

void user_menu(void);			//用户界面
void save_money(void);			//存钱
void withdraw_money(void);	//取钱
void trans_act(void);			//转帐
void query(void);				//查询
void modify_pwd(void);			//修改密码


int main()
{
	init();
	menu();
}

//初始化获取消息队列
int init(void)
{
	//debug("%s\n",__func__);
	//获取消息队列
	msgid = msgget(key,0);
	if(0 > msgid)
	{
		perror("msgget");
		return -1;
	}
	return 0;
}

//开户
void open_act(void)
{
	Account act = {};
	//发送信息类型定为 911,接受类型 119
	Msg msg = {};
	msg.type = 911;
	printf("请输入姓名:");
	get_str(act.name,20);
	printf("请输入身份证:");
	get_str(act.id,20);
	printf("请输入密码:");
	get_str(act.pwd,20);
	
	msg.act = act;
	//向服务端发送注册信息
	msgsnd(msgid,&msg,sizeof(Msg),0);
	
	//接收开发进程返回的119类型消息
	msgrcv(msgid,&msg,sizeof(Msg),119,MSG_NOERROR);
	if(-1 == msg.act.user)
	{
		puts("尊敬的客户,由于系统维护,开户失败了");
		anykey_continue();
		return;
	}
	printf("恭喜%s,开户成功\n",msg.act.name);
	printf("您的帐号为%ld\n",msg.act.user);
	anykey_continue();
	return;
}

//销户
void destroy_act(void)
{
	Account act = {};
	//发送信息类型定为 811,接受类型 118
	Msg msg = {};
	msg.type = 811;
	msg.flag = 0;
	printf("请输入姓名:");
	get_str(act.name,20);
	printf("请输入帐号:");
	scanf("%ld",&act.user);
	getchar();
	printf("请输入密码:");
	get_str(act.pwd,20);
	msg.act = act;
	//向客户端发送注册信息
	msgsnd(msgid,&msg,sizeof(Msg),0);
	//接收开发进程返回的118类型消息
	msgrcv(msgid,&msg,sizeof(Msg),118,MSG_NOERROR);
	if(1 == msg.flag)
	{	
		for(;;)
		{
			printf("是否确认销户(Y/N):");
			char cmd = getchar();
			if('Y' == cmd || 'y' == cmd)
			{
				msg.type = 811;
				msgsnd(msgid,&msg,sizeof(Msg),0);
				msgrcv(msgid,&msg,sizeof(Msg),118,MSG_NOERROR);
				if(0 == msg.flag)
				{
					puts("销户成功!");
				}
				else
				{
					puts("销户失败!");
				}
				break;
			}
			else if('N' == cmd || 'n' == cmd)
			{
				puts("已经取消销户!");
				break;
			}
		}
	}
	else if(-2 == msg.flag)
	{
		puts("此帐号不存在,销户失败!");
	}
	else if(-1 == msg.flag)
	{
		puts("输入的密码或者姓名错误,销户失败!");
	}
	
	anykey_continue();
	return;
}

//登陆
void login(void)
{
	Account act = {};
	//发送信息类型定为 711,接受类型 117
	Msg msg = {};
	msg.type = 711;
	msg.flag = 0;
	printf("请输入帐号:");
	scanf("%ld",&act.user);
	//getchar();
	printf("请输入密码:");
	get_str(act.pwd,20);
	msg.act = act;
	//向客户端发送注册信息
	msgsnd(msgid,&msg,sizeof(Msg),0);
	//接收开发进程返回的117类型消息
	msgrcv(msgid,&msg,sizeof(Msg),117,MSG_NOERROR);
	if(3 <= msg.act.lock)
	{
		puts("密码输错3次,此账户已锁定,请解锁");
		anykey_continue();
		return;
	}
	
	if(1 == msg.flag)
	{
		puts("登陆成功");
		online_user = msg.act;
		anykey_continue();
		user_menu();
	}
	else
	{
		puts("登陆失败,帐号或者密码错误!");
	}
	anykey_continue();
	return;
}

//解锁
void unlock(void)
{
	Account act = {};
	//发送信息类型定为 611,接受类型 116
	Msg msg = {};
	msg.type = 611;
	msg.flag = 0;
	printf("请输入帐号:");
	scanf("%ld",&act.user);
	//getchar();
	printf("请输入身份证:");
	get_str(act.id,20);
	msg.act = act;
	msgsnd(msgid,&msg,sizeof(Msg),0);
	msgrcv(msgid,&msg,sizeof(Msg),116,MSG_NOERROR);
		
	if(1 == msg.flag)
		puts("解锁成功");
	else if(0 == msg.flag)
		puts("此帐号并未锁定");
	else
		puts("解锁失败,输入的帐号或者身份证错误!");
	anykey_continue();
	return;
}

//存钱
void save_money(void)
{
	Msg msg = {};
	//发送信息类型定为 511,接受类型 115
	msg.type = 511;
	msg.flag = 0;
	msg.act = online_user;
	
	printf("请输入要存入的金额:");
	scanf("%lf",&msg.act.money);

	msgsnd(msgid,&msg,sizeof(Msg),0);
	msgrcv(msgid,&msg,sizeof(Msg),115,MSG_NOERROR);
	if(-1 != msg.flag)
	{
		online_user.money = msg.act.money;
		printf("======存钱成功======\n");
		printf("用户余额:%.2lf\n",msg.act.money);
	}
	else
		printf("系统正在升级,存钱失败\n");
	anykey_continue();
	return;
}

//取钱
void withdraw_money(void)
{
	Msg msg = {};
	//发送信息类型定为 411,接受类型 114
	msg.type = 411;
	msg.flag = 0;
	msg.act = online_user;
	
	printf("请输入要取出的金额:");
	scanf("%lf",&msg.act.money);

	msgsnd(msgid,&msg,sizeof(Msg),0);
	msgrcv(msgid,&msg,sizeof(Msg),114,MSG_NOERROR);
	if(-1 != msg.flag)
	{
		online_user.money = msg.act.money;
		printf("======取钱成功======\n");
		printf("用户余额:%.2lf\n",msg.act.money);
	}
	else
		printf("系统正在升级,取钱失败\n");
	anykey_continue();
	return;
}

//转帐
void trans_act(void)
{
	Msg msg = {};
	//发送信息类型定为 311,接受类型 113
	msg.type = 311;
	msg.flag = 0;
	msg.act.money = 0;
	printf("请输入要转帐的账户:");
	scanf("%ld",&msg.act.user);
	//发送信息,查询目标账户是否存在
	msgsnd(msgid,&msg,sizeof(Msg),0);
	msgrcv(msgid,&msg,sizeof(Msg),113,MSG_NOERROR);
	if(0 != msg.flag)
	{
		puts("您要转入的账户不存在,转帐失败");
		anykey_continue();
		return;
	}
	printf("请输入要转帐的金额:");
	scanf("%lf",&msg.act.money);
	if(msg.act.money > online_user.money)
	{
		puts("余额不足,转帐失败");
		anykey_continue();
		return;
	}
	//再次发送信息,给目标账户加钱
	msg.flag = 1;
	msg.type = 311;
	msgsnd(msgid,&msg,sizeof(Msg),0);
	msgrcv(msgid,&msg,sizeof(Msg),113,MSG_NOERROR);
	//再次发送信息,给账户减钱
	msg.type = 311;
	msg.flag = 2;
	msg.act.user = online_user.user;
	msgsnd(msgid,&msg,sizeof(Msg),0);
	msgrcv(msgid,&msg,sizeof(Msg),113,MSG_NOERROR);
	online_user.money = msg.act.money;
	
	puts("转帐成功");
	printf("用户余额:%.2lf\n",msg.act.money);
	anykey_continue();
	return;
}

//查询
void query(void)
{
	Msg msg = {};
	//发送信息类型定为 211,接受类型 112
	msg.type = 211;
	msg.flag = 0;
	msg.act = online_user;
	msgsnd(msgid,&msg,sizeof(Msg),0);
	msgrcv(msgid,&msg,sizeof(Msg),112,MSG_NOERROR);
	if(-1 != msg.flag)
		printf("用户余额:%.2lf\n",msg.act.money);
	else
		printf("查询失败\n");
	anykey_continue();
	return;
}

//修改密码
void modify_pwd(void)
{
	Msg msg = {};
	//发送信息类型定为 111,接受类型 110
	msg.type = 111;
	msg.flag = 0;
	msg.act.user = online_user.user;
	
	printf("请输入新密码:");
	get_str(msg.act.pwd,20);
	
	msgsnd(msgid,&msg,sizeof(Msg),0);
	msgrcv(msgid,&msg,sizeof(Msg),110,MSG_NOERROR);
	if(0 == msg.flag)
		printf("改密成功\n");
	else
		printf("改密失败\n");
	anykey_continue();
	return;
}

//用户界面
void user_menu(void)
{
	//debug("%s\n",__func__);
	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_money(); break;
			case '2':withdraw_money(); break;
			case '3':trans_act(); break;
			case '4':query(); break;
			case '5':modify_pwd(); break;
			case '0':return;
		}
	}
}

//主界面
void menu(void)
{
	//debug("%s\n",__func__);
	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_act(); break;
			case '2':destroy_act(); break;
			case '3':login(); break;
			case '4':unlock(); break;
			case '0':return;
		}
	}
}



服务端代码

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include "struct.h"
#include "tools.h"

static int msgid;
static pid_t prs_pid[9];

void sigint(int num)
{
	msgctl(msgid,IPC_RMID,NULL);
	for(int i = 0; i < 9; i++)
	{
		kill(prs_pid[i],SIGKILL);
	}
}

int main()
{
	msgid = msgget(key,IPC_CREAT|IPC_EXCL|0644);
	if(0 > msgid)
	{
		perror("msgget");
		return -1;
	}
	
	prs_pid[0] = vfork();
	if(0 == prs_pid[0])
	{
		execl("open_act","open_act",NULL);
	}
	
	prs_pid[1] = vfork();
	if(0 == prs_pid[1])
	{
		execl("destroy","destroy",NULL);	
	}
	
	prs_pid[2] = vfork();
	if(0 == prs_pid[2])
	{
		execl("login_act","login_act",NULL);	
	}
	
	prs_pid[3] = vfork();
	if(0 == prs_pid[3])
	{
		execl("unlock","unlock",NULL);	
	}
	
	prs_pid[4] = vfork();
	if(0 == prs_pid[4])
	{
		execl("save_money","save_money",NULL);	
	}
	
	prs_pid[5] = vfork();
	if(0 == prs_pid[5])
	{
		execl("withdraw_money","withdraw_money",NULL);	
	}
	
	prs_pid[6] = vfork();
	if(0 == prs_pid[6])
	{
		execl("trans_act","trans_act",NULL);	
	}
	
	prs_pid[7] = vfork();
	if(0 == prs_pid[7])
	{
		execl("query","query",NULL);	
	}
	
	prs_pid[8] = vfork();
	if(0 == prs_pid[8])
	{
		execl("modify_pwd","modify_pwd",NULL);	
	}	
	
	while(-1 != wait(NULL));
}

打开2个终端,一个 make编译所有文件,运行./server客户端
在这里插入图片描述
一个运行./client服务端
在这里插入图片描述
演示部分功能:

开户
在这里插入图片描述
在这里插入图片描述
登陆
在这里插入图片描述
在这里插入图片描述
存钱
在这里插入图片描述
在这里插入图片描述
转账
在这里插入图片描述

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值