手机缴费系统
前言
移动通信业务中,有一部分都是和手机缴费的业务相关,而手机缴费业务目前处于发展的阶段,手机缴费业务作为目前唯一的数据业务正在飞速发展中 近年来,随着中国市场经济的高速发展的情况下,社会上出现了很多新消费模式,由此移动通信行业衍生出很多新的业务,具体情况可以总结为以下几点:
这追求效率的时代,随着们生活水平的提高,消费项目,服务种类的增加,社会需要方便和快捷的缴费方式。在当今网络社会,技术成熟,发挥网络技术优势,利用网络实现快捷缴费已经成为可能。 利用电子商务网络以及众多的营业网点实时收费,在几乎不增加系统负担的情况既可缓解目前收费单位营业厅的紧张状况,又方便用户缴费,提高了费用回收率。
手机缴费系统是基于UNIX Socket和MySQL数据库
一个交易型中间件系统。在Linux环境下使用GNU C或者GNU C++,在Linux make开发工具的管理和控制下,利用Linux系统提供的Socket库和MySQL数据库在网络底层开发交易型中间件,同时简要介绍了客户端和服务器的工作模式。此模拟手机交费系统采用“客户端—中间件—服务器”模式,其中主要包括三大部分: 客户端(Client),中间件(Middleware)和服务器端(Server)。客户端(Client)主要实现用户管理、查询、交易(交费,购物等),撤销和统计等功能;中间件(Middleware)要完成与客户要求相符的功能——是本地的本地处理,否则发往服务器端——接受客户端数据,组织服务器端所需数据,重组服务端返回数据,并返回给客户方;服务器端(Server)主要实现客户端或中间件提出的业务请求并做好留迹工作。
本设计主要是利用UNIX系统提供的Socket库在网络底层,C语言,MySQL数据库,以及软件工程的思想方法和TCP/IP设计出的一个模拟手机交费中间件系统。
本设计包括了模拟手机交费系统的开发环境,设计目的,总体设计,详细设计,具体实现代码,以及设计中遇到的问题及解决方法。将服务器端(Server),中间件(Middleware)和客户端(Client)进行连接后可模拟出现实中手机交费的的功能。它可以实现手机费用查询,话费充值,打印花费
详目等基本功能。
目录
一、系统环境(硬件环境、软件环境) .............................................. 3
二、计目的 ............................................................................................. 3 三、体设计(程序设计组成框图、流程图、类图) ........................... 3
,(,程序设计组成框图: ............................................................ 3
,(,:中间件模型 ........................................................................ 4
,(,流程图 ................................................................................... 5 四、详细设计 ......................................................................................... 6
,(,设计方法 ............................................................................... 6
,(,功能模块说明 ........................................................................ 6 五、调试与测试 ..................................................................................... 8
,(,调试方法 ............................................................................... 8
,(,结果及简单分析 .................................................................... 9 六、设计中遇到的问题及解决方法 .................................................... 10
七、源程序清单 ................................................................................... 11 八、总结,收获与体会 ........................................................................ 36 九、参考文献 ....................................................................................... 36
一、系统环境(硬件环境、软件环境)
硬件环境:intel p4 3.06GHz 80G硬盘
软件环境:基于windows xp虚拟机下的Red Linux操作系统 二、计目的
本次设计的主要课题是:模拟手机缴费系统,通过对移动通信话费查询与缴费
系统全面的分析研究。针对现有系统中实时性不足而造成用户欠费太多使公司企业务进行了
业蒙受损失的问题。采用开发工具Linux+My进行系统设计。基于Uinx Socket和My,,,数据库,设计一个交易型中间件系统。提供通讯转发和协议 转换的桥梁作用。例如电子商务、银行代理业务软件等都是这种类型软件。这里的中间件是指交易型中间件。交易型中间件是指用在不同行业、不同部门间的通讯转发和协议转换的软件,在不同的行业、不同的系统间。这里主要是利用UNIX系统提供的Socket库在网络底层,开发交易型中间件。
本设计的目的是使参与设计者掌握利用软件工程的思想方法和TCP/IP设计出用于不同行业和部门间的通讯转发或协议转换软件—中间件,尤其掌握这种设计的思想和方法。本设计系统能够通过两种方式提供对移动话费信息输入、查询、编辑以及话费统计各明细项目的数据编辑,自动计算出花费的各项合计数据;可自主设定条件从而达到对话费数据的多角度查询功能;方便导入、导出数据及输出报表。
三、体设计(程序设计组成框图、流程图、类图) ,(,程序设计组成框图:
实现工具及
方法 Linux +Mysql+ VMware Workstation 基本功能
客 1.手机余客户端发送:头部(A)+ 目标(移动公司P)+手机号码
额查询 (15) +机主姓名(30)
户 中间件发送:头部(B)+ 目标(移动公司P)+标志(O)
+ 手机号码(15)+ 机主(30) +余额(20)或:头部(B)
端 目标(移动公司P)+标志(E)+出错原因
<----> 2.银行账客户端发送:头部(A)+目标(银行B)+银行账户(19)+
户余额查密码(10)
中 询: 中间件发送:头部(B)+目标(银行B)+标志(O)
+户主(30)+账号(19)+余额(20)或:头部(B)+目标(银间 行B)+标志(E)+错误信息
3.手机充客户端发送:头部(C)+手机号码(15)+银行账户(19)+件 值 银行密码(10)+充值金额(20)
中间件发送:头部(D)+标志(O)或:头部(D)+标
志(E)+错误原因
中 中间件 1.查询余额
中间件发送:头部(E)+银行账户(19)+密码(10) 间 <---->银 服务器发送:头部(F)+标志(O)+银行账号(19)+用
户名(30)+余额(20)或:头部(F)+标志(E)+出错原件 行服务器 因
2.扣款 <----中间件发送:头部(G)+银行账户(19)+密码(10)+扣款> 金额(20)
服务器发送:头部(H)+标志(O)或:头部(H)+标服
志(E)+出错原因
1.查询余额 务
中间件 中间件发送:头部(E)+手机号码(15)
器 服务器发送:头部(F)+标志(O)+手机号码(15)+机
<---->移 主姓名(30)+余额(20)或:头部(F)+标志(E)+出错
原因
动服务器 2.缴费
中间件发送:头部(G)+手机号码(15)+缴费金额(20)
服务器发送:头部(H)+标志(O)或:头部(H)+标
志(O)+出错原因
退出系统 当完成一次交易时,就可以退出系统。
,(,:中间件模型
,(,流程图
Socker()建立服务方
套接字,描述符为s
bingd()绑定套接字
与本地地址和端口
Linsten()通知TCP,Socker()建立服务方准备接受 套接字,描述符为s accept()等待客户方Connect()建立与服连接 务方链接 成功后返回与s具相
同特性的新套接字
recv()/read()读取Send()/write()向客户方数据 服务器方发送请求 服务处理及数据加 等待服务器方 send()/write向客户recv()/read读取服方提供服务结果 务方数据 Close()关闭新套接Close()关闭最初套字s,结束本次对话 接字s,结束本次对话 Close()关闭最初套
接字s,结束服务器
四、详细设计
,(,设计方法
在Linux环境下,使用GNU C或GNU C++,在UNIX/Linux make开发工具的的管理和控制下,利用UNIX/Linux Socket库在网络的底层进行开发设计。 ,(,功能模块说明
本系统主要是由一个客户机,一个中间件以及两个服务器组成,两个服务器分别负责手机直接缴费和网上银行缴费。以下即是每个模块间的联系图:
Client 1 Client 2 Log
请求1 请求2
返回 返回
中 间 件
Log (Middleware)
请求服务
响应服务
服务器端(Server) Log
Middle
ware 请求数据 返回结果
Mysql database Log
Middle ware (1)客户机:只负责发送和接收请求信息,此模块的目的就是将信息呈现给用户看,并提供相应的操作选择。此模块处理信息的过程较简单,原理如基本功能的现金支付所述,在此不再多做介绍。
(2)中间件:与客户机和服务器相连接,通过判断倒数第二个字符来判断选择
哪个服务器,具体的是把客户端发来的信息转发给哪个服务器。通过服务器反馈回来信息的特殊字符来判断此信息是由哪个服务器发送而来。简单来说,中间件在整个分布式系统中起数据总线的作用,将各种异构系统通过中间件有机地结合成一个整体。
(3)服务器:本系统有两个服务器,手机服务器(S2)和银行服务器(S1) 1)手机服务器在这一部分,需要实现的功能是直接缴费。它的过程是接收从中间件过来的信息,在手机服务器的客户账户上相应加上对应的话费,即更新手机服务器数据库。更新成功直接之后,将缴费成功的信息传回中间件。具体流程如下:
查询用户信息
缴费金额
中间件处理
更新银行数据库
现金缴纳话费工作流程图
Service2 client middle (手机服务器) 注:直接现金缴纳,不需要通过银行服务器。从客户端开始流程,最后更新手机服务器数据库,即缴费成功。
2)银行服务器在银行服务器这一块,需要实现的功能是手机网上缴费。它的过程是接收从中间件过来的信息,在客户所输入的银行账户上扣除相应的手机费用;如果在手机的服务器那一块出现问题,缴费不成功,银行服务器还负责把之前所扣除的话费给加上,具体实现流程如下:
查询用户信息
switch(v[0][0])
手机缴费成功 手机缴费失败 从银行卡扣钱 返回扣除费用
更新银行数据库
选择银行服务器后整个系统的工作流程图:
Service2 5
(手机服务器) 4
7 client middle
1 6
Service2 2 3
(银行服务器)
虚线表示在手机服务器出错,缴费失败,向银行服务器返回所交的话费。
五、调试与测试
,(,调试方法
(1)把数据库文件导入数据库
#mysql –u root
,加上后就正确了。
还有一个最可恶的问题,老是莫名奇妙的出现”段错误”,开始时摸不着头脑,就和同学一块商量,凭着各自了了的一点经验讨论,还好最后都解决了,主要时字符串末尾一定要加‘\0’,表示结束,否则可能是越界。 主要问题:
(1) 对Mysql 数据库不够了解,对很多数据结构和算法也理解不够牢固,因
此我们参考了《Linux+php+Mysql基础与提高》这本书,学到一些关于
Mysql的基础知识,才使工作能顺利的进行下去。
(2) 对套接字这样的概念不是很清楚,在老师的辅导和互联网的帮助下,了解
了一些这方面的知识,才使我们的设计开展下来。
(3) 以前对服务器,客户端只是了解理论知识,这次而要自己动手来开发服务
器,这对我们来说,是一个巨大的挑战,服务器就是一个进程,确切的说
是一个守候进程,要实现它的功能,是不容易的事情,你要学会套接字,
地址转换,服务器相关的数据结构和算法才能进行开发和设计。 (4) 还是很多基础的东西没有掌握好,基本的算法也没有完全掌握,参考了教
科书的相关内容后,才开始了我们的课程设计。
(5) 在数据库的编写时,很多要用到的数据类型而我们又没有学过的,只能借
助互联网的强大功能了,由此,我们也学到了很多相关的知识。 七、源程序清单
中间件代码:#include #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char *argv[]) {
int log(char *filepath,char *buff );
char log_file[10]="mid.log";
char log_buf[1024];
//网络通信信息
int listen_fd;//监听套接字描述符
int com_fd;//通信套接字描述符
int len;//请求方地址长度
int ret;
pid_t pid;//处理请求进程id
struct servent *sp;//存放服务器端口信息,从services文件读取
struct sockaddr_in srv_addr;//服务器地址
struct sockaddr_in clt_addr;//客户端地址
listen_fd=socket(PF_INET,SOCK_STREAM,0);//创建监听套接字
//数据库连接信息
MYSQL mysql;//MySQL连接
MYSQL_ROW row;//结果的行
MYSQL_RES *result;//查询结果
char myl_buf[1024];//存放sql语句
//初始化网络连接参数
int DataSend(char *service,char *dest,char sed_buf[1024],char rcv_buf[1024]);
if(listen_fd<0)
{
perror("创建监听套接字失败");
strcpy(log_buf,"创建监听套接字失败");
log(log_file,log_buf);
return 1;
}
//从services文件中获取服务器端口号
if((sp=getservbyname(argv[1],"tcp"))==NULL)
{
fprintf(stderr,"参数错误");
strcpy(log_buf,"参数错误");
log(log_file,log_buf);
exit(-5);
}
memset(&srv_addr,0,sizeof(srv_addr));//将srv_addr初始化为全0
//设定地址参数
srv_addr.sin_family=AF_INET;
srv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
srv_addr.sin_port=sp->s_port;
//绑定服务套接字
ret=bind(listen_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
if(ret==-1)
{
perror("绑定服务套接字失败");
strcpy(log_buf,"绑定服务套接字失败");
log(log_file,log_buf);
close(listen_fd);
return 1;
}
//监听客户连接
ret=listen(listen_fd,1024);
if(ret==-1)
{
perror("监听客户请求失败");
strcpy(log_buf,"监听客户请求失败");
log(log_file,log_buf);
close(listen_fd);
return 1;
}//连接users数据库
if(mysql_init(&mysql)==NULL)
{
fprintf(stderr,"数据连接初始失败");
strcpy(log_buf,"数据连接初始失败");
log(log_file,log_buf);
exit(-1);
}
if(!mysql_real_connect(&mysql,"localhost","root",0,"users",0,NULL,0))
{
fprintf(stderr,"数据库连接错误: %s [%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
mysql_close(&mysql);
exit(-2);
} //开始接受客户请求
printf("等待客户连接\n");
while(1)
{
len=sizeof(clt_addr);
com_fd=accept(listen_fd,(struct sockaddr*)&clt_addr,&len);
if(com_fd<0)
{
perror("接受客户端连接请求失败");
strcpy(log_buf,"接受客户端连接请求失败");
log(log_file,log_buf);
close(listen_fd);
return 1;
}
if((pid=fork())==-1)
{
printf("开创进程失败");
strcpy(log_buf,"开创进程失败");
log(log_file,log_buf);
return 1;
}
if(pid==0) //创建子进程成功
{
close(listen_fd);//关闭监听套接字
//处理接受到的数据
char send_buf[1024];
int len;
if(len=read(com_fd,send_buf,1024)>0)
{
if(send_buf[0]=='C')
{
printf("收到充值请求,信息如下\n");
printf("%s\n",send_buf);
printf("手机号码:%s\n",send_buf+2);
printf("银行账号:%s\n",send_buf+17);
printf("银行密码:%s\n",send_buf+36);
printf("充值金额:%s\n",send_buf+46);
char p_send[1024];
char p_rcv[1024];
char b_send[1024];
char b_rcv[1024];
//缴费封包
memcpy(p_send,"G",2);
memcpy(p_send+2,send_buf+2,15);
memcpy(p_send+17,send_buf+46,20); //扣款封包
memcpy(b_send,"G",2);
memcpy(b_send+2,send_buf+17,19);
memcpy(b_send+21,send_buf+36,10);
memcpy(b_send+31,send_buf+46,20);
DataSend(argv[2],argv[3],b_send,b_rcv);
printf("银行数据已发送\n");
char t[1024];
memcpy(t,"D",2);
if(b_rcv[2]=='O')
{
DataSend(argv[4],argv[5],p_send,p_rcv);
printf("移动公司数据已发送\n");
if(p_rcv[2]=='O')
{
printf("充值成功\n");
memcpy(t+2,"O",2);
write(com_fd,t,1024);
}
else if(p_rcv[2]=='E')
{
memcpy(t+2,"E",2);
memcpy(t+4,p_rcv+4,50);
write(com_fd,t,1024);
}
else if(b_rcv[2]=='E')
{
memcpy(t+2,"E",2);
memcpy(t+4,b_rcv+4,50);
}
}
if(send_buf[0]=='A')
{
printf("收到查询请求:\n");
if(send_buf[2]=='B')
{
printf("收到银行查询,信息如下\n");
printf("%s\n",send_buf);
printf("%s\n",send_buf+2);
printf("银行账号:%s\n",send_buf+4);
printf("银行密码:%s\n",send_buf+23);
char tmp[1024];
char tmp_r[1024];
memcpy(tmp,"E",2);
memcpy(tmp+2,send_buf+4,19);
memcpy(tmp+21,send_buf+23,10);
printf("银行账号:%s\n",tmp+2);
printf("银行密码:%s\n",tmp+21);
DataSend(argv[2],argv[3],tmp,tmp_r);
printf("%s\n",tmp_r);
printf("%s\n",tmp_r+2);
printf("%s\n",tmp_r+4);
printf("%s\n",tmp_r+6);
printf("%s\n",tmp_r+36);
printf("%s\n",tmp_r+55);
write(com_fd,tmp_r,1024);
}
else if(send_buf[2]=='P')
{
printf("收到手机查询,信息如下\n");
printf("%s\n",send_buf);
printf("%s\n",send_buf+2);
printf("手机号码:%s\n",send_buf+4);
char tmp[1024];
char tmp_r[1024];
memcpy(tmp,"E",2);
memcpy(tmp+2,send_buf+4,15);
printf("手机账号:%s\n",tmp+2);
DataSend(argv[4],argv[5],tmp,tmp_r);
printf("%s\n",tmp_r);
printf("%s\n",tmp_r+2);
printf("%s\n",tmp_r+4);
printf("%s\n",tmp_r+6);
printf("%s\n",tmp_r+21);
printf("%s\n",tmp_r+57);
write(com_fd,tmp_r,1024);
}
}
}
exit(0);
}
//回到父进程
if(pid>0)
{
wait(0);
close(com_fd);//关闭通信套接字
continue;
}
}
int DataSend(char *service,char *dest,char sed_buf[1024],char rcv_buf[1024])//参数为服务端口端口号和主机名及需要发送的数据
{
struct hostent *hp;//服务地址
struct sockaddr_in sin;//指明连接地址信息
struct servent *sp;//服务端口
int s;//连接描述符
//获取服务端口号
if((sp=getservbyname(service,"tcp"))==NULL)
{
fprintf(stderr,"Error: getservbyname");
exit(-5);
}
//获取目的主机
if((hp=gethostbyname(dest))==0)
{
fprintf(stderr,"Error: gethostbyname");
exit(-6);
}
//初始化服务套接字
bzero(&sin,sizeof(sin));
bcopy(hp->h_addr,&sin.sin_addr,hp->h_length);
sin.sin_family=hp->h_addrtype;
sin.sin_port=sp->s_port;
if((s=socket(AF_INET,SOCK_STREAM,0))==-1)
{
fprintf(stderr,"Error: socket");
exit(-6);
}
if(connect(s,&sin,sizeof(sin))==-1)
{
fprintf(stderr,"Error: connect");
close(s);
exit(-6);
}
//发送数据
//fprintf(stderr,"%s is sending request message: %s\n",argv[0],sed_buf);
if(write(s,sed_buf,1024)!=1024) //to server
{
fprintf(stderr,"Write Socket s ERROR\n!");
close(s);
exit(-1);
}
if(read(s,rcv_buf,1025)==0) //get replay from server
{
fprintf(stderr,"Read Socket s Error\n");
close(s);
exit(-2);
}
printf("%s\n",rcv_buf);
//printf("%s get reply: %s\n",argv[0],sed_buf);
close(s);
}
}
int log(char *filepath,char *buff )
{
int fd;
time_t t = time(0);
char tmp[64];
strftime( tmp, sizeof(tmp), "%Y/%m/%d %X %A ",localtime(&t) );
if((fd=open(filepath,O_WRONLY|O_CREAT|O_APPEND,0644))==-1)
{
fprintf(stderr,"Log file %s open error!\a\n",log);
exit(-1);
}
write(fd,tmp,strlen(tmp));
write(fd,":",2);
write(fd,buff,strlen(buff));
write(fd,"\n",2);
close(fd);
}
银行端:
int log(char *filepath,char *buff ) {
int fd;
time_t t = time(0);
char tmp[64];
strftime( tmp, sizeof(tmp), "%Y/%m/%d %X %A ",localtime(&t) );
if((fd=open(filepath,O_WRONLY|O_CREAT|O_APPEND,0644))==-1)
{
fprintf(stderr,"Log file %s open error!\a\n",log);
exit(-1);
}
write(fd,tmp,strlen(tmp));
write(fd,":",2);
write(fd,buff,strlen(buff));
write(fd,"\n",2);
close(fd);
}
int main(int argc,char *argv[]) {
int log(char *filepath,char *buff );
char log_file[10]="bank.log";
char log_buf[1024];
int fd;//日志文件描述符
//网络通信信息
int listen_fd;//监听套接字描述符
int com_fd;//通信套接字描述符
int len;//请求方地址长度
int ret;
pid_t pid;//处理请求进程id
struct servent *sp;//存放服务器端口信息,从services文件读取
struct sockaddr_in srv_addr;//服务器地址
struct sockaddr_in clt_addr;//客户端地址
listen_fd=socket(PF_INET,SOCK_STREAM,0);//创建监听套接字
//数据库连接信息
MYSQL mysql;//MySQL连接
MYSQL_ROW row;//结果的行
MYSQL_RES *result;//查询结果
char myl_buf[1024];//存放sql语句
//初始化网络连接参数
if(listen_fd<0)
{
perror("创建监听套接字失败");
strcat(log_buf,"创建监听套接字失败");
log(log_file,log_buf);
return 1;
}
//从services文件中获取服务器端口号
if((sp=getservbyname(argv[1],"tcp"))==NULL)
{
fprintf(stderr,"参数错误");
exit(-5);
}
memset(&srv_addr,0,sizeof(srv_addr));//将srv_addr初始化为全0
//设定地址参数
srv_addr.sin_family=AF_INET;
srv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
srv_addr.sin_port=sp->s_port;
//绑定服务套接字
ret=bind(listen_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
if(ret==-1)
{
perror("绑定服务套接字失败");
strcat(log_buf,"绑定服务套接字失败");
log(log_file,log_buf);
close(listen_fd);
return 1;
}
//监听客户连接
ret=listen(listen_fd,1024);
if(ret==-1)
{
perror("监听客户请求失败");
strcat(log_buf,"监听客户请求失败");
log(log_file,log_buf);
close(listen_fd);
return 1;
}
//连接users数据库
if(mysql_init(&mysql)==NULL)
{
fprintf(stderr,"数据连接初始失败");
strcat(log_buf,"数据连接初始失败");
log(log_file,log_buf);
exit(-1);
}
if(!mysql_real_connect(&mysql,"localhost","root",0,"bank",0,NULL,0))
{
fprintf(stderr,"数据库连接错误: %s [%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
mysql_close(&mysql);
exit(-2);
}
//开始接受客户请求
printf("等待客户连接\n");
while(1)
{
len=sizeof(clt_addr);
com_fd=accept(listen_fd,(struct sockaddr*)&clt_addr,&len);
if(com_fd<0)
{
perror("接受客户端连接请求失败");
strcat(log_buf,"接受客户端连接请求失败");
log(log_file,log_buf);
close(listen_fd);
return 1;
}
if((pid=fork())==-1)
{
printf("开创进程失败");
return 1;
}
//创建子进程成功
if(pid==0)
{
close(listen_fd);//关闭监听套接字
//处理接受到的数据
char send_buf[1024];
int len;
if(len=read(com_fd,send_buf,1024)>0)
{
if(send_buf[0]=='G')
{
printf("收到充值请求,信息如下\n");
printf("%s\n",send_buf);
printf("银行账号%s\n",send_buf+2);
printf("银行密码%s\n",send_buf+21);
printf("充值金额%s\n",send_buf+31);
//更新数据库
sprintf(myl_buf,"select * from bank where number=\"%s\"",send_buf+2);
if(mysql_query(&mysql,myl_buf)!=0)
{
fprintf(stderr,"数据查询错误: %s
[%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
mysql_close(&mysql);
exit(-3);
}
if((result=mysql_store_result(&mysql))==NULL)
{
fprintf(stderr,"存放数据失败: %s
[%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
mysql_free_result(result);
mysql_close(&mysql);
exit(-4);
};
if((mysql_num_rows(result))==0)
{
printf("用户不存在!\n");
strcat(log_buf,"用户不存在!");
log(log_file,log_buf);
}
row=mysql_fetch_row(result);
if(strcmp(row[1],send_buf+21)!=0)
{
printf("密码错误\n");
}
else
{
float money;
money=atof(row[3])-atof(send_buf+31);
printf("余额变更为:%f\n",money);
if(money>=0)
{
char buff[1024];
sprintf(myl_buf,"update bank set money=%f where
number=\"%s\"",money,row[0]);
if(mysql_query(&mysql,myl_buf)!=0)
{
fprintf(stderr,"数据查询错误: %s
[%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
mysql_close(&mysql);
exit(-3);
}
else
{
printf("更新成功~~");
}
memcpy(buff,"H",2);
memcpy(buff+2,"O",2);
write(com_fd,buff,1024);
}
}
}
if(send_buf[0]=='E')
{
printf("收到银行查询,信息如下\n");
printf("%s\n",send_buf);
printf("银行账号:%s\n",send_buf+2);
printf("银行密码:%s\n",send_buf+21);
char number[19];//银行账号
char password[10];//密码
char name[30];//户主姓名
sprintf(myl_buf,"select * from bank where
number=\"%s\"",send_buf+2);
if(mysql_query(&mysql,myl_buf)!=0)
{
fprintf(stderr,"数据查询错误: %s [%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
mysql_close(&mysql);
exit(-3);
}
if((result=mysql_store_result(&mysql))==NULL)
{
fprintf(stderr,"存放数据失败: %s [%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
mysql_free_result(result);
mysql_close(&mysql);
exit(-4);
};
if((mysql_num_rows(result))==0)
{
printf("用户不存在!\n");
strcat(log_buf,"用户不存在!");
log(log_file,log_buf);
}
row=mysql_fetch_row(result);
if(strcmp(row[1],send_buf+21)!=0)
{
printf("密码错误\n");
strcat(log_buf,"密码错误!");
log(log_file,log_buf);
}
else
{
printf("%s\n",row[2]);
printf("%s\n",row[0]);
printf("%s\n",row[3]);
char tmp[1024];
memcpy(tmp,"B",2);
memcpy(tmp+2,"B",2);
memcpy(tmp+4,"O",2);
memcpy(tmp+6,row[2],30);
memcpy(tmp+36,row[0],19);
memcpy(tmp+55,row[3],20);
write(com_fd,tmp,1024);
printf("%i",sizeof(tmp));
close(com_fd);
}
}
}
exit(0);
}
//回到父进程
if(pid>0)
{
wait(0);
close(com_fd);//关闭通信套接字
continue;
}
}
}
手机端:
int log(char *filepath,char *buff )
{
int fd;
time_t t = time(0);
char tmp[64];
strftime( tmp, sizeof(tmp), "%Y/%m/%d %X %A ",localtime(&t) );
if((fd=open(filepath,O_WRONLY|O_CREAT|O_APPEND,0644))==-1)
{
fprintf(stderr,"Log file %s open error!\a\n",log);
exit(-1);
}
write(fd,tmp,strlen(tmp));
write(fd,":",2);
write(fd,buff,strlen(buff));
write(fd,"\n",2);
close(fd);
}
int main(int argc,char *argv[]) {
int log(char *filepath,char *buff );
char log_file[10]="phone.log";
char log_buf[1024];//网络通信信息
int fd;//日志文件描述符
int listen_fd;//监听套接字描述符
int com_fd;//通信套接字描述符
int len;//请求方地址长度
int ret;
pid_t pid;//处理请求进程id
struct servent *sp;//存放服务器端口信息,从services文件读取
struct sockaddr_in srv_addr;//服务器地址
struct sockaddr_in clt_addr;//客户端地址
listen_fd=socket(PF_INET,SOCK_STREAM,0);//创建监听套接字
char buff[1024];
//数据库连接信息
MYSQL mysql;//MySQL连接
MYSQL_ROW row;//结果的行
MYSQL_RES *result;//查询结果
char myl_buf[1024];//存放sql语句
//初始化网络连接参数
if(listen_fd<0)
{
perror("创建监听套接字失败");
strcat(log_buf,"创建监听套接字失败");
log(log_file,log_buf);
return 1; }
//从services文件中获取服务器端口号
if((sp=getservbyname(argv[1],"tcp"))==NULL)
{
fprintf(stderr,"参数错误");
exit(-5);
}
memset(&srv_addr,0,sizeof(srv_addr));//将srv_addr初始化为全0
//设定地址参数
srv_addr.sin_family=AF_INET;
srv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
srv_addr.sin_port=sp->s_port;
//绑定服务套接字
ret=bind(listen_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
if(ret==-1)
{
perror("绑定服务套接字失败");
strcat(log_buf,"绑定服务套接字失败");
log(log_file,log_buf);
close(listen_fd);
return 1;
}
ret=listen(listen_fd,1024); //监听客户连接
if(ret==-1)
{
perror("监听客户请求失败");
strcat(log_buf,"监听客户请求失败");
log(log_file,log_buf);
close(listen_fd);
return 1;
}
if(mysql_init(&mysql)==NULL) //连接users数据库
{
fprintf(stderr,"数据连接初始失败");
strcat(log_buf,"数据连接初始失败");
log(log_file,log_buf);
exit(-1);
}
if(!mysql_real_connect(&mysql,"localhost","root",0,"phone",0,NULL,0))
{
fprintf(stderr,"数据库连接错误: %s
[%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
strcat(log_buf,"数据库连接错误");
log(log_file,log_buf);
mysql_close(&mysql);
exit(-2);
} //开始接受客户请求
printf("等待客户连接\n");
while(1)
{
len=sizeof(clt_addr);
com_fd=accept(listen_fd,(struct sockaddr*)&clt_addr,&len);
if(com_fd<0)
{
perror("接受客户端连接请求失败");
strcat(log_buf,"接受客户端连接请求失败");
log(log_file,log_buf);
close(listen_fd);
return 1;
}
if((pid=fork())==-1)
{
printf("开创进程失败");
strcat(log_buf,"开创进程失败");
log(log_file,log_buf);
return 1;
}
//创建子进程成功
if(pid==0)
{
close(listen_fd);//关闭监听套接字
char send_buf[1024];
int len;
if(len=read(com_fd,send_buf,1024)>0)
{
if(send_buf[0]=='G')
{
printf("收到缴费请求,信息如下\n");
printf("%s\n",send_buf);
printf("手机号码%s\n",send_buf+2);
printf("缴费金额%s\n",send_buf+17);
sprintf(myl_buf,"select *from phone where
number=\"%s\"",send_buf+2);
if(mysql_query(&mysql,myl_buf)!=0)
{
fprintf(stderr,"数据查询错误: %s [%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
mysql_close(&mysql);
memcpy(buff,"H",2);
memcpy(buff+2,"E",2);
memcpy(buff+4,"银行服务器错误",14);
exit(-3);
}
if((result=mysql_store_result(&mysql))==NULL)
{
fprintf(stderr,"存放数据失败: %s [%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
mysql_free_result(result);
mysql_close(&mysql);
exit(-4);
memcpy(buff,"H",2);
memcpy(buff+2,"E",2);
memcpy(buff+4,"银行服务器错误",20);
strcat(log_buf,"银行服务器错误");
log(log_file,log_buf);
};
row=mysql_fetch_row(result);
if((mysql_num_rows(result))==0)
{
printf("手机号码不存在!\n");
memcpy(buff,"H",2);
memcpy(buff+2,"E",2);
memcpy(buff+4,"手机号码不存在!",20);
strcat(log_buf,"手机号码不存在!");
log(log_file,log_buf);
} else
{
float money;
money=atof(row[2])+atof(send_buf+17);
if(money>=0)
{
printf("余额变更为:%f\n",money);
sprintf(myl_buf,"update phone set money=%f where
number=\"%s\"",money,row[0]);
if(mysql_query(&mysql,myl_buf)!=0)
{
fprintf(stderr,"数据查询错误: %s [%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
mysql_close(&mysql);
exit(-3);
}else
{
printf("更新成功\n");
memcpy(buff,"H",2);
memcpy(buff+2,"O",2);
}
}
}
//printf("错误信息:%s\n",buff+4);
write(com_fd,buff,1024);
}
}
if(send_buf[0]=='E')
{
printf("收到手机余额查询,信息如下\n");
printf("%s\n",send_buf);
printf("手机号码:%s\n",send_buf+2);
char number[19];//银行账号
char name[30];//户主姓名
sprintf(myl_buf,"select * from phone where number=\"%s\"",send_buf+2);
if(mysql_query(&mysql,myl_buf)!=0)
{
fprintf(stderr,"数据查询错误: %s [%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
mysql_close(&mysql);
memcpy(buff,"F",2);
memcpy(buff+2,"E",2);
memcpy(buff+4,"服务器错误",14);
exit(-3);
}
if((result=mysql_store_result(&mysql))==NULL)
{
fprintf(stderr,"存放数据失败: %s [%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
mysql_free_result(result);
mysql_close(&mysql);
exit(-4);
memcpy(buff,"F",2);
memcpy(buff+2,"E",2);
memcpy(buff+4,"服务器错误",20);
};
row=mysql_fetch_row(result);
if((mysql_num_rows(result))==0)
{
strcat(log_buf,"用户不存在!");
log(log_file,log_buf);
printf("用户不存在!\n");
memcpy(buff,"F",2);
memcpy(buff+2,"E",2);
memcpy(buff+4,"用户不存在!",20);
}else
{
printf("%s\n",row[0]);
printf("%s\n",row[1]);
printf("%s\n",row[2]);
memcpy(buff,"B",2);
memcpy(buff+2,"P",2);
memcpy(buff+4,"O",2);
memcpy(buff+6,row[0],15);
memcpy(buff+21,row[1],30);
memcpy(buff+57,row[2],20);
//sprintf(tmp+55,"%s",row[3]);
}
write(com_fd,buff,1024);
}
exit(0);
}
if(pid>0)
{
wait(0);
close(com_fd);//关闭通信套接字
continue;
}
}
}
客户端:
int log(char *filepath,char *buff ) {
int fd;
time_t t = time(0);
char tmp[64];
strftime( tmp, sizeof(tmp), "%Y/%m/%d %X %A ",localtime(&t) );
if((fd=open(filepath,O_WRONLY|O_CREAT|O_APPEND,0644))==-1)
{
fprintf(stderr,"Log file %s open error!\a\n",log);
exit(-1);
}
write(fd,tmp,strlen(tmp));
write(fd,":",2);
write(fd,buff,strlen(buff));
write(fd,"\n",2);
close(fd);
}
int main(int argc,char * argv[]) {
int log(char *filepath,char *buff );
char log_buf[1024];
int fd;//日志文件描述符
char log_file[10]="clt.log";//日志文件
char user[20];//用户,用于登陆客户端
char user_p[10];//密码,用户登陆客户端
char pname[20];//机主姓名
char phone[15];//手机号码
float phone_m;//手机余额
char bname[20];//银行账号中名字
char number[19];//银行账号
char password[10];//银行密码
float bank_m;//银行账户余额
char money[20];//充值金额
MYSQL mysql;//MySQL连接
MYSQL_ROW row;//结果的行
MYSQL_RES *result;//查询结果
char myl_buf[1024];//存放sql语句
char send_buf[1024];//发送缓冲
char recive_buf[1024];//接收缓冲
int connect_fd;//连接描述符
int len;
struct servent *sp;//服务端口信息
struct hostent *hp;//服务器地址
int ret;
static struct sockaddr_in srv_addr;
//连接users数据库
if(mysql_init(&mysql)==NULL)
{
fprintf(stderr,"数据连接初始失败");
exit(-1);
}
if(!mysql_real_connect(&mysql,"localhost","root",0,"users",0,NULL,0))
{
fprintf(stderr,"数据库连接错误: %s
[%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
mysql_close(&mysql);
exit(-2);
} system("clear");
login:
printf("请输入用户名:\n");
scanf("%s",user);
printf("请输入密码:\n");
scanf("%s",user_p);
//验证用户名与密码
sprintf(myl_buf,"select * from users where name=\"%s\"",user);
if(mysql_query(&mysql,myl_buf)!=0)
{
fprintf(stderr,"数据查询错误: %s [%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
mysql_close(&mysql);
exit(-3);
}if((result=mysql_store_result(&mysql))==NULL)
{
fprintf(stderr,"存放数据失败: %s [%d]\n",mysql_error(&mysql),mysql_errno(&mysql));
mysql_free_result(result);
mysql_close(&mysql);
exit(-4);
};if((mysql_num_rows(result))==0)
{
printf("用户不存在!\n");
goto login;
}
row=mysql_fetch_row(result);
if(strcmp(row[1],user_p)!=0)
{
printf("密码错误\n");
goto login;
}
system("clear");
printf("%s 登陆成功\n",user);
interface:
system("clear");
if((sp=getservbyname(argv[1],"tcp"))==NULL)
{
fprintf(stderr,"端口号获取错误,请检查第一个参数,并确保在services文件里有该参数");
exit(-1);
}
if((hp=gethostbyname(argv[2]))==0)
{
fprintf(stderr,"中间件地址获取失败,请检查第二个参数,并确保hosts文件里有对
应项");
exit(-2);
}
memset(&srv_addr,0,sizeof(srv_addr));
srv_addr.sin_family=AF_INET;
bcopy(hp->h_addr,&srv_addr.sin_addr,hp->h_length);
srv_addr.sin_port=sp->s_port;
connect_fd=socket(PF_INET,SOCK_STREAM,0);
if(connect_fd<0)
{
perror("创建通信套接字失败");
return 1;
}
ret=connect(connect_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
if(ret==-1)
{
perror("无法连接到服务器");
close(connect_fd);
return 1;
}
printf("=========欢迎您使用手机缴费系统=======\n");
printf("1.给手机缴费 2.查询银行账户\n");
printf("3.查询手机余额 4.退出系统\n");
printf("请选择数字操作:");
char choice;
scanf("%s",&choice);
switch(choice)
{case '1':
printf("");
printf("请输入手机号码\n");
scanf("%s",phone);
printf("请输入银行账号\n");
scanf("%s",number);
printf("请输入银行密码\n");
scanf("%s",password);
printf("请输入缴费金额");
scanf("%s",money);
memcpy(send_buf,"C",2);
memcpy(send_buf+2,phone,15);
memcpy(send_buf+17,number,19);
memcpy(send_buf+36,password,10);
memcpy(send_buf+46,money,20);
printf("以下为充值信息:\n");
printf("%s\n",send_buf);
printf("手机号码:%s\n",send_buf+2);
printf("银行账户%s\n",send_buf+17);
printf("充值金额%s\n",send_buf+46);
write(connect_fd,send_buf,1024);
if(len=read(connect_fd,recive_buf,1024)>0)
{
printf("收到数据\n");
printf("---------充值成功!!--------\n");
printf("按回车键返回……\n");
strcat(log_buf,"………………给手机缴费…………");
strcat(log_buf,"电话号码:");
strcat(log_buf,phone);
strcat(log_buf," ");
strcat(log_buf,"银行账号:");
strcat(log_buf,number);
strcat(log_buf," ");
strcat(log_buf,"充值话费:");
strcat(log_buf,money);
log(log_file,log_buf);
char stdinBuff[1024];
fgets(stdinBuff, 1024, stdin);
getchar();
goto interface;
} else {
char stdinBuff[1024];
fgets(stdinBuff, 1024, stdin);
printf("充值失败^^^^^^%s\n",recive_buf+4);
printf("按回车键返回……\n");
strcat(log_buf,"电话号码:");
strcat(log_buf,phone);
strcat(log_buf," 账户不存在,充值失败~");
log(log_file,log_buf);
getchar();
goto interface;
}break;
case '2':
printf("");
printf("请输入银行账号\n");
scanf("%s",number);
printf("请输入银行密码\n");
scanf("%s",password);
memcpy(send_buf,"A",2);
memcpy(send_buf+2,"B",2);
memcpy(send_buf+4,number,19);
memcpy(send_buf+23,password,10);
printf("以下为查询信息:\n");
printf("%s\n",send_buf);
printf("银行账户%s\n",send_buf+4);
printf("密码%s\n",send_buf+23);
write(connect_fd,send_buf,1024);
printf("发送数据成功。。\n");
if(len=read(connect_fd,recive_buf,1024)>0)
{
printf("收到数据\n");
if(recive_buf[0]=='B')
{if(recive_buf[2]=='B')
{ if(recive_buf[4]=='O')
{
printf("---------查询成功!!--------\n");
printf("银行户主:%s\n",recive_buf+6);
printf("银行账号:%s\n",recive_buf+36);
printf("银行余额:%s\n",recive_buf+55);
printf("按回车键返回……\n");
strcat(log_buf,"………………查询银行账户…………");
strcat(log_buf,"银行户主:");
strcat(log_buf,user);
strcat(log_buf," ");
strcat(log_buf,"银行账号:");
strcat(log_buf,number);
log(log_file,log_buf);
char stdinBuff[1024];
fgets(stdinBuff, 1024, stdin);
getchar();
goto interface;
}
{
printf("查询失败:%s\n",recive_buf+6);
printf("按回车键返回……\n");
strcat(log_buf," 查询账户失败~");
log(log_file,log_buf);
char stdinBuff[1024];
fgets(stdinBuff, 1024, stdin);
getchar();
goto interface;
}
}
}
}break;
case '3':
printf("");
printf("请输入手机号码\n");
scanf("%s",phone);
memcpy(send_buf,"A",2);
memcpy(send_buf+2,"P",2);
memcpy(send_buf+4,phone,15);
printf("以下为查询信息:\n");
printf("%s\n",send_buf);
printf("手机号码:%s\n",send_buf+4);
write(connect_fd,send_buf,1024);
if(len=read(connect_fd,recive_buf,1024)>0)
{if(recive_buf[0]=='B')
{
printf("---------查询成功!!--------\n");
printf("电话号码:%s\n",recive_buf+6);
printf("手机户主:%s\n",recive_buf+21);
printf("账户余额:%s\n",recive_buf+57);
strcat(log_buf,"………………查询手机余额…………");
strcat(log_buf,"电话号码:");
strcat(log_buf,phone);
strcat(log_buf," ");
strcat(log_buf,"手机户主:");
strcat(log_buf,user);
log(log_file,log_buf);
printf("按回车键返回……\n");
char stdinBuff[1024];
fgets(stdinBuff, 1024, stdin);
getchar();
goto interface;
}else
{
printf("查询失败:号码不存在\n",recive_buf+5);
printf("按回车键返回……\n");
strcat(log_buf,"话费余额查询失败~");
log(log_file,log_buf);
char stdinBuff[1024];
fgets(stdinBuff, 1024, stdin);
getchar();
goto interface;
}
}
}
case '4':
close(connect_fd);
printf("退出成功\n");
strcat(log_buf,"退出成功~");
log(log_file,log_buf);
exit(0);
break;
default:
printf("输入错误,请按回车键后重新选择\n");
char stdinBuff[1024];
fgets(stdinBuff, 1024, stdin);
getchar();
goto interface;
break;
}
}
八、总结,收获与体会
课程设计是培养学生综合运用所学知识,发现,提出,分析和解决实际问题,锻炼实践能力的重要环节,是对学生实际工作能力的具体训练和考察过程。
经过两个星期,在我们集体的共同努力下还是把课程设计给完成了,可谓是大快人心,但过程是很曲折和艰难的。在此之前,我们已做过好几次课程设计,虽说在这方面我们每个人都应有一些经验,但我们这次却要做的是网络编程于LINUX的结合,对每个人来说都是一个新的难题,所以大家心里都没底。随着网络在实际生活中应用的不断拓展,C/S服务模式越来越普遍,但是其缺点也越来越突出。为了克服其缺点,人们开发了中间件,我们的课程设计就是模拟客户端,中间件,服务器模式,为以后的实际应用做好准备。刚开始大家都不知怎么做,但在老师的指引和同学们相互交流下,经大家一点一点努力下,最终突破了一个一个的困难,两周的努力终于见到了胜利的果实。
回顾起此次linux课程设计,至今我仍感慨颇多,的确,从选题到定稿,从理论到实践,在整整两星期的日子里,可以说得是苦多于甜,但是可以学到很多很多的的东西,同时不仅可以巩固了以前所学过的知识,而且学到了很多在书本上所没有学到过的知识。通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和独立思考的能力。在设计的过程中遇到问题,可以说得是困难重重,这毕竟第一次做的,难免会遇到过各种各样的问题,同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固,比如对linux的基本操作不熟练,对套接字等概念不了解„„
通过这次课程设计之后,不仅对以往学过的知识有了新的理解,还学习了许多新的知识,也提高了自己的动手能力和合作能力。在实践中学习,在学习中实践,只有这样才能更快的发现问题,更好的解决问题。课程设计的意义就在这学与问的过程中的提高与发展,最终连接理论知识与实践。
九、参考文献
,1, Linux 操作系统 ,2, Linux+php+mysql网络编程 ,3, Linux/Unix C编程入门 ,4, 红帽Linux9 从入门到精通……电子工业出版社出版
thirdapi.dll 第三方开发接口说明
{
函数说明: 初始化服务器连接 参数说明: aserverip - 服务器地址 aport-端口
返回说明: 0 -成功
-1 -失败
}
int initnet(char aserverip[30],int aport);
{
函数说明: 分销商登入验证 参数说明: aloginname - 用户名 loginpw- 密码
返回说明: 0 -成功
-1 -失败
1-密码错误
2-无此用户
3-该帐号不能在此计算机登入
}
int login(char aloginname[20],char aloginpw[16]);
{
函数说明: 缴费
参数说明: aphonenum - 缴费号码 apaymoney- 缴费金额,精确到分 acityid- 城市编号
athirdtrjn -对接系统的缴费流水 atrjnmainid-我方系统返回的流水号 返回说明: 0 -成功
-1 -失败
1-充值命令已发送,服务器未返回信息 2-运营商充值账户余额不足
3-账户余额不足
6-暂不支持该运营商的缴费
7-连接该运营商设备失败
8-同一号码在 2 分钟内不能重复充值
10-该帐号不能在此计算机缴费 }
int phonepay(char aphonenum[20],int apaymoney,int acityid,char athirdtrjn[30],int
* atrjnmainid);
{
函数说明: 根据日期,号码查询缴费状态 参数说明:
abegindate- 起始日期,格式 yyyy-mm-dd, aenddate- 结束日期
aphonenum - 缴费号码
返回说明: -1 -查询失败
0 -充值失败
1-充值中
2-充值成功
}
int getrecord(char * abegindate, char * aenddate, char * aphonenum);
{
函数说明: 根据流水号查询缴费状态 参数说明:
atrjnmainid- 我方系统返回的流水号
返回说明: -1 -查询失败
0 -充值失败
1-充值中
2-充值成功
}
int getrecordbytrjnmainid(int atrjnmainid);
{
函数说明: 根据第三方系统流水号查询缴费状态
参数说明:
athirdtrjn- 第三方系统流水号
返回说明: -1 -查询失败
0 -充值失败
1-充值中
2-充值成功
}
int getrecordbythirdtrjn(char * athirdtrjn);
{
函数说明: 查询账户余额
参数说明:
aaccountye- 余额,精确到分
返回说明: -1 -查询失败
0-充值成功
}
int getaccunt(int * aaccountye);
{
函数说明: 退出网络连接 返回说明: 0 -成功
-1 -失败
}
int closenet;