网络编程项目(模拟ATM存取款机)

项目名称:模拟ATM 存取款机

编程语言:C语言

开发环境:linux

项目功能:

        (1) 用户注册登录

        (2) 登录成功之后可以进行查询余额,存款,取款,销户

项目实现:

        (1) 客户端和服务器端之间使用tcp通信

        (2) 服务器端采用IO多路复用并发服务器

        (3) 客户端给服务器端发送消息,服务器端对收到的消息进行解析之后执行对应的操作,并操作数据库

代码:

一:客户端:

结构体定义:

typedef struct atm
{
	char name[20];
	char num[20];
	char id[20];
	char passwd[20];;
	char money[20];
}Atm;

各项功能的菜单函数

void menu()
{
	printf("*****************************\n");
	printf("\n");
	printf("\t\t1.注册\n");
	printf("\t\t2.登陆\n");
	printf("\t\t3.退出\n");
	printf("\n");
	printf("*****************************\n");
}
void menu2()
{
	printf("*****************************\n");
	printf("\n");
	printf("\t\t4.查询余额\n");
	printf("\t\t5.存款\n");
	printf("\t\t6.取款\n");
	printf("\t\t7.销户\n");
	printf("\t\t3.退出\n");
	printf("\n");
	printf("******************************\n");
}

 客户端的主函数:

#include"net.h"

int main(int argc, char *argv[])
{
	Atm a1;
	memset(&a1,0,sizeof(a1));
	//c创建套接字
	int tcp_socket = tcp_client(argv[1],atoi(argv[2]));
	if(tcp_socket < 0)
	{
		return -1;
	}
	char buf[100]={'\0'};
	int op,ret,option=1;
	while(1)
	{
		if(option < 2)
		{
			menu();
			printf("请输入选项:\n");
			scanf("%d",&op);
			send(tcp_socket,&op,sizeof(op),0);
			if(3 == op)
			{
				printf("退出成功!\n");
				break;
			}
			switch(op)
			{
			case 1:
				//注册
				registe(tcp_socket);
				break;
			case 2:
				//登陆
				option=login(tcp_socket,&a1);
				printf("id=%s,passwd=%s\n",a1.id,a1.passwd);
				break;
			}
		}
		else if(option == 2)
		{
			menu2();
			printf("请输入选项:\n");
			scanf("%d",&op);
			send(tcp_socket,&op,sizeof(op),0);
			if(3 == op)
			{
				printf("退出成功!\n");
				break;
			}
			switch(op)
			{
				case 4:
					//查询余额
					inquire(tcp_socket,&a1);
					break;
				case 5:
					//存款
					save(tcp_socket,&a1);
					break;
				case 6:
					//取款
					take(tcp_socket,&a1);
					break;
				case 7:
					//销户
					option = delete1(tcp_socket,&a1);
					break;
				default:
					printf("输入错误,请重新输入!\n");
			}
		}
	}
	close(tcp_socket);
	return 0;
}

tcpt通信的搭建:

#include"net.h"

int tcp_client(char *ip,int port)
{
	int tcp_socket = socket(AF_INET,SOCK_STREAM,0);
	if(tcp_socket < 0)
	{
		perror("create error");
		return -1;
	}
	printf("socket ok\n");
	struct sockaddr_in server;
	memset(&server,'\0',sizeof(server));
	server.sin_family = AF_INET;
	server.sin_port = htons(port);
	server.sin_addr.s_addr = inet_addr(ip);
	if(connect(tcp_socket,(struct sockaddr *)&server,sizeof(server)) < 0)
	{
		perror("connect error");
		return -1;
	}
	printf("connect ok\n");
	//允许端口和地址复用
	int on = 1;
	setsockopt(tcp_socket,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	return tcp_socket;
}

 注册:


//注册
void registe(int tcp_socket)
{
	Atm a1={'\0'};
	int ret;
	char buf[100]={'\0'};
		printf("请输入姓名:\n");
		scanf("%s",a1.name);
		printf("请输入身份证号:\n");
		scanf("%s",a1.num);
		printf("请输入想要设置的密码:\n");
		scanf("%s",a1.passwd);
		memset(buf,'\0',sizeof(buf));
		sprintf(buf,"%s#%s#%s#%s#%s",a1.name,a1.num,a1.id,a1.passwd,a1.money);
		send(tcp_socket,buf,sizeof(buf),0);
		recv(tcp_socket,&ret,sizeof(ret),0);
		if(0==ret)
		{
			printf("该身份证号已被注册\n");
		}
		else
		{
			printf("注册成功!卡号为:%d\n",ret);
		}

}

登录:

//登陆
int login(int tcp_socket,Atm *a11)
{
	int ret;
	Atm a1 = {'\0'};
	char buf[100]={'\0'};
	printf("请输入卡号:");
	scanf("%s",a1.id);
	printf("请输入密码:\n");
	scanf("%s",a1.passwd);
	memset(buf,'\0',sizeof(buf));
	sprintf(buf,"%s#%s",a1.id,a1.passwd);
		send(tcp_socket,buf,sizeof(buf),0);
		recv(tcp_socket,&ret,sizeof(ret),0);
		if(-1==ret)
		{
			printf("该卡号未被注册\n");
			return 1;
			
		}
		else if(ret == 0)
		{
			printf("密码输入错误!\n");
			return 1;
		}
		else
		{
			*a11 = a1;
			printf("登陆成功!\n");
			return 2;
		}
}

 查询余额:

void inquire(int tcp_socket,Atm *a1)
{
	int ret;
	send(tcp_socket,a1->id,sizeof(a1->id),0);
	recv(tcp_socket,&ret,sizeof(ret),0);
	if(ret < 0)
	{
		printf("inquire error\n");
	}
	else
	{
		sprintf(a1->money,"%d",ret);
		printf("%s\n",a1->money);
	}
}

 存款:

void save(int tcp_socket,Atm *a1)
{
	int ret;
	int save_money;
	char pwd[100] = {'0'};
	char pwd2[100] = {'0'};
	sprintf(pwd2,"%s",a1->passwd);
	memset(a1,0,sizeof(a1));
	printf("请输入您要存入的金额:\n");
	scanf("%d",&save_money);
	printf("请输入您的密码:\n");
	scanf("%s",pwd);
	if(strcmp(pwd,pwd2)!=0){
	printf("密码错误!\n");
	return;	
	}

	send(tcp_socket,&save_money,sizeof(save_money),0);
	send(tcp_socket,a1->id,sizeof(a1->id),0);
	recv(tcp_socket,&ret,sizeof(ret),0);
	if(ret > 0)
	{
		printf("存入成功!余额为:%d\n",ret);
	}
	else
	{
		printf("存入失败!\n");
	}
}

取款: 

void take(int tcp_socket,Atm *a1)
{
	int ret;
	int save_money;
	char pwd[100] = {'0'};
	char pwd2[100] = {'0'};
	sprintf(pwd2,"%s",a1->passwd);
	memset(a1,0,sizeof(a1));
	printf("请输入您要取出的金额:\n");
	scanf("%d",&save_money);
	printf("请输入您的密码:\n");
	scanf("%s",pwd);
	if(strcmp(pwd,pwd2)!=0){
	printf("密码错误!\n");
	return;	
	}

	send(tcp_socket,&save_money,sizeof(save_money),0);
	send(tcp_socket,a1->id,sizeof(a1->id),0);
	recv(tcp_socket,&ret,sizeof(ret),0);
	if(ret >= 0)
	{
		printf("取出成功!余额为:%d\n",ret);
	}
	else if(ret==-1)
	{
		printf("存入失败!\n");
	}else{
		printf("余额不足!\n");
	}

}

 销户:

int delete1(int tcp_socket,Atm *a1)
{
	int ret;
	send(tcp_socket,a1->id,sizeof(a1->id),0);
	recv(tcp_socket,&ret,sizeof(ret),0);
	if(ret < 0)
	{
		printf("销户失败\n");
		return 2;
	}
	else
	{
		printf("销户成功\n");
		return 1;
	}
}	

 二:服务器端

主函数:

#include"net.h"
int main(int argc, char *argv[])
{
	//创建并打开数据库
	sqlite3 *db;
	if(sqlite3_open("user.db",&db) != SQLITE_OK)
	{
		printf("open error\n");
		return -1;
	}
	printf("open ok\n");
	//创建表
	if(create_user(db) < 0)
	{
		return -1;
	}
	int listenfd=tcp_socket(argv[1],atoi(argv[2]));
	if(listenfd < 0)
	{
		return -1;
	}
	fd_set rdfs,temp;
	FD_ZERO(&rdfs);
	FD_ZERO(&temp);
	FD_SET(listenfd,&rdfs);

	int newfd;
	Atm a1;
	int i;

	while(1)
	{
		temp = rdfs;
		if(select(FD_SETSIZE,&temp,NULL,NULL,NULL)<0)
		{
			perror("select error\n");
			close(listenfd);
			return -1;
		}
		for(i=0;i<FD_SETSIZE;i++)
		{
			if(FD_ISSET(i,&temp))
			{
				if(i == listenfd)
				{
					//监听是否有人介入
					struct sockaddr_in user;
					int len = sizeof(user);
					newfd = accept(i,(struct sockaddr *)&user,&len);
					if(newfd < 0)
					{
						return -1;
					}
					printf("有新用户连接\n");
					printf("ip:%s port:%d\n",inet_ntoa(user.sin_addr),user.sin_port);
					FD_SET(newfd,&rdfs);
				}
				else
				{
					//通信套接字
					int op,option;
					int value;
					int ret = -1;
					char *str[10]={'\0'};
					char buf[100]={'\0'};
					int n = recv(i,&op,sizeof(op),0);
					printf("op = %d\n",op);
					if(n < 0)
					{
						return -1;
					}
					else if(n==0)
					{
						//客户端退出
						close(i);
						FD_CLR(i,&rdfs);
						continue;
					}
					else
					{
						if(op<=2)
						{
							switch(op)
							{
								case 1:
									//注册
									memset(buf,0,sizeof(buf));
									recv(i,buf,sizeof(buf),0);
									paseStr(buf,str);	
									ret = registe(db,str);
									if(ret == 0)
									{
										value = 0;
										
										continue;
									}
									else
									{
										send(i,&ret,sizeof(ret),0);
									}
									break;
								case 2:
									//登陆
									memset(buf,0,sizeof(buf));
									recv(i,buf,sizeof(buf),0);
									paseStr(buf,str);
									ret = login(db,str);
									if(ret < 0)
									{
										send(i,&ret,sizeof(ret),0);
									}
									else if(ret == 0)
									{
										send(i,&ret,sizeof(ret),0);
									}
									else
									{
										//option = 2;
										send(i,&ret,sizeof(ret),0);
									}
									break;
							}
						}
						else if(op > 2)
						{
							if(3==op)
							{
								close(i);
								FD_CLR(i,&rdfs);
								continue;
							}
							int money;
							switch(op)
							{
								case 4:
									//查询余额
									recv(i,buf,sizeof(buf),0);
									ret = select1(db,buf);
									if(ret < 0)
									{
										send(i,&ret,sizeof(ret),0);
									}
									else
									{
										send(i,&ret,sizeof(ret),0);
									}
									break;
								case 5:
									//存款	
									recv(i,&money,sizeof(money),0);
									recv(i,buf,sizeof(buf),0);
									ret = save(db,buf,money);
									if(ret < 0)
									{
										send(i,&ret,sizeof(ret),0);
									}
									else
									{
										send(i,&ret,sizeof(ret),0);
									}
									break;
								case 6:
									//存款	
									recv(i,&money,sizeof(money),0);
									recv(i,buf,sizeof(buf),0);
									ret = take(db,buf,money);
									if(ret < 0)
									{
										send(i,&ret,sizeof(ret),0);
									}
									else
									{
										send(i,&ret,sizeof(ret),0);
									}
									break;
								case 7:
									//销户
									recv(i,buf,sizeof(buf),0);
									ret = delete1(db,buf);
									if(ret < 0)
									{
										send(i,&ret,sizeof(ret),0);
									}
									else
									{
										send(i,&ret,sizeof(ret),0);
									}
									break;

							}
						}
					}
				}
			}
		}
	}
	close(listenfd);
	return 0;
}

tcp通信:

#include"net.h"

int tcp_socket(char *ip,int port)
{
	int socket_fd = socket(AF_INET,SOCK_STREAM,0);
	if(-1 == socket_fd)
	{
		perror("socket error");
		return -1;
	}
	printf("socket ok\n");
	struct sockaddr_in server;
	memset(&server,'\0',sizeof(server));
	server.sin_family = AF_INET;
	server.sin_port = htons(port);
	server.sin_addr.s_addr = inet_addr(ip);
	int on=1;
	setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	if(bind(socket_fd,(struct sockaddr *)&server,sizeof(server)) < 0)
	{
		perror("bind error");
		return -1;
	}
	printf("bind ok\n");
	if(listen(socket_fd,5) < 0)
	{
		perror("listen error");
		return -1;
	}
	printf("listen ok\n");
	return socket_fd;
}

解析函数:

void paseStr(char *buf,char *pstr[])
{
	pstr[0]=buf;
	int i=0,j=0;
	while(buf[i]!='\0')
	{
		if('#' == buf[i])
		{
			j++;
			buf[i]='\0';
			pstr[j]=&buf[i+1];
		}
		i++;
	}
}

表的创建:

int create_user(sqlite3 *db)
{
	char *errmsg = NULL;
	char sql[]="create table user (name text,num text,id text,passwd text,money text)";
	int rc = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
	if(rc != SQLITE_OK && rc != 1)
	{
		printf("create error:%s\nrc=%d\n",errmsg,rc);
		sqlite3_free(errmsg);
		return -1;
	}
	else
	{
		printf("create usertable ok\n");
		return 0;
	}
}

注册:

int registe(sqlite3 *db,char *str[])
{
	char **result;
	int nrow,ncolumn,i,j;
	char sql[]="select max(id) from user";
	sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,NULL);
	int id = atoi(result[nrow])+1;
	char sql2[100]={'\0'};
	sprintf(sql2,"insert into user (name,num,id,passwd,money) values ('%s','%s','%d','%s','0')",str[0],str[1],id,str[3]);
	if(sqlite3_exec(db,sql2,NULL,NULL,NULL))
	{
		return -1;
	}
	return id;
}

登录:

int login(sqlite3 *db,char *str[])
{
	char **result;
	int nrow,ncolumn,i,j;
	char sql[100]={'\0'};
	sprintf(sql,"select passwd from user where id = '%s'",str[0]);
	sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,NULL);
    if(nrow<=0)
        return -1;
    if(strcmp(result[nrow],str[1])!=0)    
        return 0;
    return 1;

}

查询余额:

int select1(sqlite3 *db,char *str)
{
	char **result;
	int nrow,ncolumn,i,j;
	char sql[100]={'\0'};
	sprintf(sql,"select money from user where id = '%s'",str);
	sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,NULL);
    if(nrow<=0)
        return -1;
    return atoi(result[nrow]);
}

存款:

int save(sqlite3 *db,char *str,int money)
{
	char **result;
	int nrow,ncolumn,i,j;
	char sql[100]={'\0'};
	sprintf(sql,"select money from user where id = '%s'",str);
	sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,NULL);
	if(nrow<=0)return -1;
	int new_money = atoi(result[nrow]) + money;
	sprintf(sql,"update user set money = '%d' where id = '%s'",new_money,str);

	if(sqlite3_exec(db,sql,NULL,NULL,NULL))
	{
		return -1;
	}
	return new_money;
}

取款:

int take(sqlite3 *db,char *str,int money)
{
	char **result;
	int nrow,ncolumn,i,j;
	char sql[100]={'\0'};
	sprintf(sql,"select money from user where id = '%s'",str);
	sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,NULL);
	if(nrow<=0)return -1;
	int new_money = atoi(result[nrow]) - money;
	if(new_money<0)return -2;
	sprintf(sql,"update user set money = '%d' where id = '%s'",new_money,str);
	if(sqlite3_exec(db,sql,NULL,NULL,NULL))
	{
		return -1;
	}
	return new_money;
}

销户:

int delete1(sqlite3 *db,char *str)
{
	char **result;
	int nrow,ncolumn,i,j;
	char sql[100]={'\0'};
	sprintf(sql,"delete from user where id = '%s'",str);
	if(sqlite3_exec(db,sql,NULL,NULL,NULL))
	{
		return -1;
	}
return 0;
}

 输出结果:

注册:

 登录:

 存款:

取款:

销户:

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 账户类(满分50分) 版本1:满分10 分 设计Account1 类,包含: ■ 一个名为 id 的int 类型的私有数据域(默认值为 0),长度为 6 位。 ■ 一个名为 balance的double 类型的私有数据域(默认值为 0)。 ■ 一个名为 annualInterestRate 的double 类型的私有数据域存储当前利率(默认值为 0)。 假设所有的账户都有相同的利率。 ■ 一个名为 dateCreated 的Date 类型的私有数据域存储账户的开户日期。 ■ 一个能创建默认账户的无参构造方法。 ■ 一个能创建带特定 id 和初始余额的构造方法,初始余额不能为负数。 ■ id 、balance和annualInterestRate 的访问器和修改器。 ■ dateCreated 的访问器。 ■ 一个名为 getMonthlyInterestRate 的方法返回月利率。 ■ 一个名为 withDraw 的方法从账户提取特定金额。 ■ 一个名为 deposit 的方法向账户存人特定金额。 ■ double 类型的数据域保留 2 位小数。 ■ 成员方法和数据域应进行基本的合理性检查。 设计测试类 ATMMachine1: ■ 创建一个有 100 个账户的数组,其 id 为0,1,2,...99, 并初始化收支为 1000 美元。 ■ 主菜单如下(可参考教材中文版 P296或英文版 P367): Main menu 1: check balance 2: withdraw 3: deposit 版本2:满分20 分 扩展Account1 类为Account2 类: ■ Account2 类继承 Account1 类。 ■ 为Account2 类新增一个名为 password 的String 类型的私有数据域存储账号密码。 password 只能为字母或数字,长度不能小于 6 且不能大于 10。密码显示时为*******。 ■ 为Account2 类新增一个名为 name的String 类型的私有数据域存储客户名字。 ■ 为Account2 类新增一个名为 transactions 的ArrayList 类型的新数据域,其为客户存 储交易记录。这要求新建一个名为 Transaction 的类,类的定义请参照教材中文版 P327或英 文版P404。每笔交易都是 Transaction 类的一个实例。 ■ 新增一个带初始余额的构造方法,其 id 随产生,但不能与当前系统的 id 重复。 若初始余额的参数为负数,则抛出一个自定义异常并在当前构造方法中进行处理。 ■ 重写方法 withDraw ,要求支取的金额为 100 的整数倍,并且当日支取金额不能超过 5000,支取金额不允许透支。每进行一次操作应向 transactions 数组线性表添加一笔交易。 ■ 重写方法 deposit ,要求每进行一次操作应向 transactions 数组线性表添加一笔交易。 ■ 新增一个方法 changePassword ,只有旧密码正确,新密码符合要求,且两次输入相 同的情况下才可以成功修改密码 设计测试类 ATMMachine2,其主菜单如下(可参考教材中文版 P296或英文版 P367): Main menu 0:create a account 1: check balance 2: withdraw 3: deposit 4:details of the transaction 5: change password 6:exit ■ 若用户选择新建一个账号,则应提示用户输入账号 password 、balance 和 annualInterestRate ,其中 id 随产生。新产生的账户应序列化到名为 accounts.dat 的文件中。 所有账户只能通过这种方式产生。 ■ 所有用户操作结果应同步到 accounts.dat 文件中相应账户中。 ■ 所有用户操作应有友好、简介的提示语。 版本3:满分20 分 请参照银行的 AT M界面,在 Account2 类的基础上开发一个 GUI 界面的AT M系统。 要求界面应模拟小键盘,并且账户信息读、写于文件 accounts.dat 。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值