河南城建学院
《软件实习2》设计说明书
设计题目: 手机缴费系统 专 业: 计算机科学与技术 指导教师: 班 级: 学 号: 姓 名: 同 组 人:
计算机科学与工程系
2010年9月9日
前言
随着现代社会的发展,信息交流已经成为一种重要的社会资源。手机是个人通讯终端的一个重要设备,它已经渗入到了社会生活的方方面面。同时保持个人手机的在线状态,也已经是很多人的共识,这也变成是社会生活的一种必要。
为广大用户提供手机服务的运营商为了方便客户的使用,也为客户提供了多种缴费方式,用以满足客户的需求。常见的缴费方式中,主要常见的是一下两种:第一种是直接使用现金缴费,另一种是手机用户通过银行账号直接进行缴费。两种缴费方式对运营商提供的数据等具有其各自独特的特点,而对于运营商而言,因为需要保存的数据具有多样性,不方便管理。因此为了缴费的统一和方便,我们需要设计一种中间件,来屏蔽掉底层缴费方式的差别。从而方便运营商和客户的使用和管理。
C/S是在专用服务器网络结构的基础上发展起来的。在这种结构的网络中,可以将多种需要处理的工作分别分配给相应的客户机和服务器来完成。因此,网络可客户机和服务器并没有一定的界限,必要时两者可以互换。在这种网络中,到底谁为客户机、谁为服务器完全按照其当时所扮演的角色来确定。一般定义是:提出服务请求的一方称为“客户机”,而提供服务的一方则称为“服务器”。
客户机/服务器(C/S)网络的信息服务系统通常由计算机平台、网络平台和数据库平台组成。这里的C/S信息系统,在硬件条件不变的情况下,根据其作用可划分为几个部分:第一部分为前端,即客户机。前端是一个运行在客户机上并向服务器发送信息,并接收服务器信息的小型应用程序,因此,前端实际就是服务器上应用程序的一个接口;第二部分为后端,即服务器。后端计算机上应当 运行基于C/S模式的后台程序,如SQL Server。服务器程序可以应用于各类计算机平台上,从微机、小型机直到大型计算机。第三部分为连接件,即起连接作用的软件和硬件。其中软件连接主要包括网络协议,网络应用接口和数据库的连接接口等,而硬件连接主要有网卡和通信介质等。
中间件,从本质上是对分布式应用的抽象,它抛开了与应用相关的业务的细节,保留了典型的分布交互模式的关键特征,将纷繁复杂的分布式系统经过提炼和必要的隔离后,以统一的层面形式呈现给应用。它在整个分布式系统中起数据总线的作用,将各种异构系统通过中间件有机地结合成一个整体。
我们这里的中间件是指交易型中间件,交易型中间件是指用在不同行业、不同部门间的通讯转发和协议转换的软件,在不同的行业、不同的系统间提供通讯转发和协议转换的桥梁作用。例如电子商务、银行代理业务软件等都是这种类型的软件。本设计主要是利用UNIX系统提供的Socket库在网络底层,C语言,MySQL数据库,以及软件工程的思想方法和TCP/IP设计出的一个模拟手机交费系统。
目 录
一、系统配置: .......................................... 4 二、设计目的: .......................................... 4 三、总体设计: .......................................... 4 四、详细设计: .......................................... 6
(一)、现金支付 ................................................. 6
(二)、网上缴费 ................................................. 7
(三)、查询 ..................................................... 7
(四)、退出 ..................................................... 7
五、调试以及测试方法: .................................. 13 六、设计中遇到的问题及解决方法。 ........................ 15 七、源程序清单 ......................................... 15 八、运行结果 ........................................... 54 九、总结,收获与体会.................................... 55 十、参考文献 ........................................... 56
3
一、系统配置:
在Linux环境下,使用GNU C或GNU C++,在UNIX/Linux make开发工具的管理和控制下,利用UNIX/Linux Socket库在网络的底层进行开发设计。服务器数据库要求使用Linux提供的免费的MySQL。开发时主要用到C访问MySql的接口程序MySql C API。
二、设计目的:
本软件需要设置了一个银行数据库,用来模拟通过银行进行手机缴费。同时设计了一个只具有一些基本简单功能的中间件,采用这个中间件来屏蔽掉分别采用现金缴费和银行缴费两种方式在底层数据上的差别。
采用开发工具Linux+Mysql进行系统设计。基于UNIX Socket和MySQL数据库,设计一个交易型中间件系统。提供通讯转发和协议转换的桥梁作用。这里的中间件是指交易型中间件。交易型中间件是指用在不同行业、不同部门间的通讯转发和协议转换的软件,在不同的行业、不同的系统间提供通讯转发和协议转换的桥梁作用。
程序完成后可以能够通过两种方式提供对手机话费信息输入、缴纳、查询等,从而实现对整个系统的一个简单模拟
三、总体设计:
本次设计重要主要包含有三个方面; 1.客户端(client) 2.中间件(middle)
3.服务器端(包含有一个(phoneSer)手机话费服务器和一个(bankSer)银行服务器)
程序设计组成框图
实现方法 功能 Linux +Mysql+ VMware Workstation
现金缴费 银行缴费 简单查询 退出系统
首先查询手机服务器是否存在将要缴费的手机号,然后返回,再将缴纳金额写入手机数据库。 首先查询手机服务器,以确定存在缴费手机号,然后返回。在查询银行服务器,以确定存在对应帐号和足够余款。将数据分别写入银行和手机数据库。 进入银行缴费界面,输入手机号后,在手机数据库中查询该手机的花费情况,并返回。 完成交易,返回上一级或者退出系统。 中间件模型:
流程图
5
四、详细设计:
(一)、现金支付
客户到操作台缴纳费用,选择现金支付方式后,首先由操作员登录,输入用户的手机号码后,客户端根据用户提供的手机号码向中间件发送请求,中间件收到请求后,接收客户方数据;组织服务器phoneSer查询手机号码并组织数据返回给中间件和客户端,查询成功后,由操作员输入缴费金额以及密码,重新组织数据建立连接,并组织服务器数据,然后返回。
6
(二)、网上缴费
客户到操作台缴纳费用,首先由操作员登录,选择网上缴费方式后,输入用户的手机号码,客户端根据用户提供的手机号码向中间件发送请求,中间件收到请求后,接收客户方数据;组织服务器phoneSer所需数据;重组服务方返回数据,并返回给客户方已确定是否存在该手机号,然后输入银行账户和缴费金额,客户端根据用户提供的手机号码向中间件发送请求,中间件收到请求后,接收客户方数据;组织服务器bankSer所需数据;重组服务方返回数据。并把数据传输给服务器phoneSer,以完成整个操作。
(三)、查询
在网络缴费的方式下,通过输入手机号码就可以得到手机用户的基本信息,包含用户名,手机号,手机余额。
(四)、退出
1、函数说明
Socket套接字的相关函数
(1) socket()
int socket(int domain, int type, int protocol);
该调用要接收3个参数,根据这3个参数建立一个套接字,并将相应的资源分配给它 同时返回一个整型套接字号,只和一个特定的协议相联系.出错时返回值-1。
(2) bind()
int bind(int sockfd, struct sockaddr *my_addr, int addrlen); sockfd 是调用 socket 返回的文件描述符。my_addr 是指向数据结构 struct sockaddr 的指针,它保存你的地址(即端口和 IP 地址) 信息。 addrlen 设置为 sizeof(struct sockaddr)。函数的作用是将特定的端口和套接字联系起来。
(3)listen()
int listen(int sockfd, int backlog);
sockfd 是调用 socket() 返回的套接字文件描述符。backlog 是在进入 队列中允许的连接数目
(4) connect()
7
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); sockfd 是系统调用 socket() 返回的套接字文件描述符。serv_addr 是保存着目的地端口和 IP 地址的数据结构 struct sockaddr。addrlen 设置 为 sizeof(struct sockaddr)。
(5)accept()
Int accept(int sockfd, void *addr, int addrlen);
sockfd是和 listen() 中一样的套接字描述符。addr 是个指 向局部的数据结构 sockaddr_in 的指针。规定了接入的信息所要去的地 方。同样,在错误时返回-1,并设置全局错误变量 errno。
(6)close()
.int close(sockfd);
它将防止套接字上更多的数据的读写。任何在另一端读写套接字的企 图都将返回错误信息。
(7)strcat()
extern char *strcat(char *dest,char *src);
src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。返回指向dest的指针。函数实现的功能是把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\\0')并添加'\\0'。
(8)stpcpy()
extern char *stpcpy(char *dest,char *src);
src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。返回指向dest结尾处字符(NULL)的指针。函数实现的功能是把src所指由NULL结束的字符串复制到dest所指的数组中。
(9)write() 系统调用格式:
number = write(handle, buffer, n) ;
handle是一个已经打开的文件句柄,表示将数据写入这个文件句柄所表示的文件内。buffer表示缓冲区,也就是把这个缓冲区的数据写入文件句柄所表示的文件内。n表示调用一次write操作,应该写如多少字符。number表示系统实际写入的字符数量。如果调用write失败,则系统返回-1给number。函数实现的功能是将某个文件缓冲区的数据,写入某个文件内。
(10)read() 系统调用格式:
number = read(handle, buffer ,n) ;
handle这是一个已经打开的文件句柄,表示从这个文件句柄所代表的文件读取数据。buffer指缓冲区,即读取的数据会被放到这个缓冲区中去。 n表示
8
调用一次read操作,应该读多少数量的字符。number:表示系统实际所读取的字符数量。函数实现的功能是
(11)atoi(将字符串转换成整形数); atoi(row[1])函数说明
atoi()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\\0')才结束转换,并将结果返回。 2.接口
Mysql提供有多种开发接口:PHP,ODBC,PERL,C/C++,JAVA
C常用的开发接口有:
mysql_init,mysql_real_connect,mysql_query,mysql_store_result,mysql_fetch_row,mysql_free_result,mysql_close,mysql_init (1)mysql_init
作用:是初始化MYSQL变量,为mysql_real_connect()做准备。 用法:MYSQL *mysql_init(MYSQL *mysql) 返回值:MYSQL句柄或描述符;内存不足是为NULL; (2)mysql_real_connect 功能:链接mysql数据库;
用法:MYSQL *mysql_real_connect(MYSQL *mysql,\\ const char *host, const char *user, const char *passwd, const char *db, unsigned int client_flag)
说明:如果port!=0,则将作为TCP/IP端口使用,默认为0;如果
unix_socket!=NULL,则可指定socket或命名PIPE,默认为NULL;Client_flag可以指定特定的值(略),默认为0. (3)mysql_query 功能:查询实施
用法:int mysql_query(MYSQL *mysql, const char *query) 说明:query为数据库操作命令字符串,本义是查询(select),可包括select,update,insert,delete等对数据库操作的命令。mysql_query不能用来处理二进制数据,处理二进制数据可使用mysql_real_query。 返回值:0表示正常,非0表示发生了错误。 (4)mysql_store_resul
功能:结果集处理。如果使用mysql_query运行的是一个SELECT语句,或其它可以返回结果的查询,可用函数mysql_store_result来访问返回结果并并将其
9
\\ \\
unsigned int port, const char *unix_socket, \\
保存在一个变量中,以便做进一步处理。 用法:
MYSQL_RES *mysql_store_result(MYSQL *mysql) MYSQL_RES *mysql_use_result(MYSQL *mysql) 说明:mysql为mysql_real_connect函数的返回值。 (5)结果集的使用
使用了mysql_store_result函数保存结果后,可以使用以下函数对结果集进行处理。
①获得结果集中的行数:
my_ulonglong mysql_num_rows(MYSQL_RES *result) ②获得结果集行的域字段数:
unsigned int mysql_num_fields(MYSQL_RES *result) unsigned int mysql_num_fields(MYSQL *mysql) ③读取结果集中的一行:
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result) ④获取结果集中行的域段数:
unsigned int mysql_field_count(MYSQL *mysql) ⑤获得结果集中的域的属性:
MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result) ⑥获得域属性数组:
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result) ⑦查询被update、delete、insert等受影响的行: my_ulonglong mysql_affected_rows(MYSQL *mysql) (6)善后工作
当对数据库使用完毕后,应对所创建的变量等进行释放: mysql_free_result(result); mysql_close(&mysql); (7)错误处理
方法有2:利用函数的返回值来判断函数执行是否正确;2.使用mysql提供的错误号和错误信息:
错误号:unsigned int mysql_errno(MYSQL *mysql) 错误信息:char *mysql_error(MYSQL *mysql) 3.字节顺序
网络字节顺序:TCP/IP使用大端字节来传输协议信息。
大端(尾)数(big-endian)把高位字节放在低地址,而小尾(端)数(little-endian)则把高位字节存放在高地址空间。
10
需要在机器字节顺序与网络字节顺序转换的可使用下列函数: unsignd int htonl(unsigned int hostlong) unsignd short htons(unsigned int hostshort) unsignd int nhtonl(unsigned int netlong) unsignd int nhtons(unsigned int netshort)
前两个是正向的,后两者是反向的。这时里的“长整数”指的是32位,而不是C语言的长整数。
4.主机信息及相关数据结构和函数
struct hostent { char char int int char };
*h_name;
// Official name of host
**h_aliases; // Alias list. h_addrtype; // Host address type h_length;
// Length of address
// List of addrs from NS
**h_addr_list;
参见netdb.h
主机信息及相关数据结构和函数
#include struct hostent *gethostbyname(const char *name) name:为主机名。可以是域名,也可在/etc/hosts中定义。 struct hostent *gethostbyadress(const char *addr, int len, int type) addr::是一个指向in_addr的结构(见netinet/in.h); len指明addr的长度; type:对于SCOK_STREAM,type为AF_INET。 5.服务器端相关的数据结构和函数 struct servent { }; 参见netdb.h 6.服务器端相关的数据结构和函数 #include struct servent *getservbyname(const char *name, const char *protocal); 11 char char int char *s_name; s_port; // Official service name. // Port number. // Protocol to use. **s_aliases; // Alias list. *s_proto; name与protocal均定义在/etc/services中: name:服务名; protocal:为协议 struct servent *getservbyport(int port, const char *protocal); 直接使用数字作为端口号,建议不要这样做,因为不便配置。 IP socket地址 #include short int sin_family; sin_addr; // AF_INET // port No. // IP addr. unsigned short int sin_port; struct in_addr 手机话费服务器 (phoneSer) 银行服务器 (bankSer) 中间件 (middle) 客户(client) 1、客户机:只负责发送和接收请求信息,此模块的目的就是将信息呈现给用户看,并提供相应的操作选择。此模块处理信息的过程较简单,原理如基本功能的现金支付所述,在此不再多做介绍。 2、中间件:与客户机和服务器相连接,通过判断倒数第二个字符来判断选择哪个服务器,具体的是把客户端发来的信息转发给哪个服务器。通过服务器反馈回来信息的特殊字符来判断此信息是由哪个服务器发送而来。简单来说,中间件在整个分布式系统中起数据总线的作用,将各种异构系统通过中间件有机地结合成一个整体。 3、服务器:本系统有两个服务器,手机服务器(S2)和银行服务器(S1) (1)手机服务器 12 现金缴费时,手机服务器的工作流程: 操作员登录 否 输入手机号 是否存在匹 配手机号 是 手机帐号数据库 (phoneSer.Sh) 写入并完成操作 输入缴纳金额 银行缴费是手机服务器和银行服务器的 操作员登陆 否 符合则分别写入并完成操作 输入手机号 帐号和余额是否匹配 否 是否存在手机帐号 是 输入缴费金额 输入使用的银行账户 读入并比对 手机帐号收据库(phoneSer) 银行账户数据库 (bankSer) 五、调试以及测试方法: 数据库的安装版本为mysql-devel-3.23.54a-11.i386.rpm 安装方法为# rpm –ivh mysql-devel-3.23.54a-11.i386.rpm 13 (1)把数据库文件导入数据库 #mysql mysql >source middle.sh; mysql >source bankSer.sh; mysql >source phoneSer.sh; (2)启动Mysql 数据(以phoneSer为例) #show database; #use phoneSer; #show tables; #select * from opr_list; (3)对程序进行编译连接 #gcc –o b bankSer.c –L/usr/lib/mysql -lmysqlclient #gcc –o p phoneSer.c –L/usr/lib/mysql -lmysqlclient #gcc –o m middle.c –L/usr/lib/mysql -lmysqlclient #gcc –o c client.c –L/usr/lib/mysql -lmysqlclient (4) 创建服务端口 由于在数据库中已经将服务端口固化,因此服务端口的创建必须符合固化后的端口。 #ivi /etc/services 进入新创建三个名字 bankSer 5676/tcp phoneSer middle 5677/tcp 5678/tcp 保存并退出vi (5) 运行程序 #./b bankSer 切换到终端2 #./p phoneSer 切换到终端3 #./m middle 切换到终端4 #./c middle localhost 14 六、设计中遇到的问题及解决方法。 这是我们在学习的过程中第一次使用Socket编程,实现网络通讯。同时也是对数据库使用的一次重要的实践,由于编写程序的经验有限,上机实践少,因此在系统的实现时候在调试过程中遇到了很多新的问题:比如: (1)数据库连接问题。 (2)Socket编程逻辑实现过程中出现连接不上的问题。 (3)对指针使用过程中出现很多难以预料的问题---段错误,空指针等等。 (4)中间件的编写几逻辑实现的问题。 总之,在程序的编写和测试的过程都每天都遇到了很多平时上机练习时候没有出现过的问题,总是让我们摸不着头脑,但是在老师的帮助下,借助网络查询、图书查询等方便快截的手段对以上遇到的问题一一解决,虽然最终的程序不是很完善,但是通过我们的努力,也基本完成需求,最主要的是我们都得到了这次课程设计过程中的很多的编程经验。 在测试过程中,我们首先是按照模拟指定的用户,对于数据库先使用固定的SQL语句,对程序和数据库进行测试和调试。在确认程序的正确性后,在对程序的部分语句进行加工修改,完成了用户想要的功能和结果。善后工作 错误处理方法有: 1.利用函数的返回值来判断函数执行是否正确; 2.使用mysql提供的错误号和错误信息: 错误号:unsigned int mysql_errno(MYSQL *mysql) 错误信息:char *mysql_error(MYSQL *mysql) 七、源程序清单 客户端 #include #define ECHOFLAGS (ECHO | ECHOE | ECHOK | ECHONL) 15 void strsplit(char *sourceStr,char **v,char d); int getpasswd(char* passwd, int size); int set_disp_mode(int fd,int option); main(int argc,char **argv) { struct hostent *hp; struct sockaddr_in sin; struct servent *sp; char connbuf[80],buf[80],oprname[20],usrname[20],bankno[20],bankpwd[20]; char quebuf[80],readbuf[80],queoprpwd[20],queusrpwd[20]; char oprpwd[20],usrpwd[20]; char phoneno[12],testStr[10],tmp[10]; int s,pid; char money[10]; int k=1,t=1,m=1,n=1,q=1,r=1,w=1,x=1,z=1; char *service,*dest; char option,chose,ch[5]; char d='-',**v=(char**)malloc(sizeof(char*) * 10); if(argc==3){ service=argv[1]; dest=argv[2]; } else { fprintf(stderr,\"NO service assigned!\\nUsage:\"); fprintf(stderr,\"%s service_name destination!\\n\",argv[0]); fprintf(stderr,\"Note: service_name is defined in /etc/services\\n\"); fprintf(stderr,\" destination is defined in /etc/hosts\\n\"); exit(-1); } while(k) { k=1,t=1,m=1,n=1,q=1,r=1,w=1,z=1; printf(\"\\ ---------- 手机缴费----------\\n\\ ****************************** \\n\"); printf(\"\\\ 1.现金交费\\n\\\ 2.网上交费\\n\\\ 3.查询\\n\\\ 4.退出\\n\"); printf(\"请选择:\"); scanf(\"%c\",&option); switch(option) { case '1': while(t) { 16 system(\"clear\"); printf(\"\\ ----------- 现金交费----------\\n\"); printf(\"请登录!(输入'exit'返回上一级)\\n\"); printf(\"请输入用户名(或exit):\"); scanf(\"%s\",&oprname); if(strcmp(oprname,\"exit\")==0) { m=0; break; } getchar(); set_disp_mode(STDIN_FILENO,0); //调用getpasswd函数获得用户输入的密码 getpasswd(oprpwd, sizeof(oprpwd)); set_disp_mode(STDIN_FILENO,1); if((sp=getservbyname(service,\"tcp\"))==NULL){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); exit(-1); } if((hp=gethostbyname(dest))==0){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); exit(-1); } 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,\"服务器会话出错!请稍后再试!\\n\"); exit(-1); } if(connect(s,(struct sockaddr*)&sin,sizeof(sin))==-1){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); close(s); exit(-1); } sprintf(buf,\"phoneSer-0-%s-%s\",oprname,oprpwd); if(write(s,buf,rec_length)!=rec_length){ //to server fprintf(stderr,\"Write Socket is ERROR!\\n\"); fprintf(stderr,\"按任意键返回...\\n\"); getchar(); close(s); exit(-1); } 17 if(read(s,buf,rec_length)==0){ //get replay from server fprintf(stderr,\"Read Socket s Error!\\n\"); fprintf(stderr,\"按任意键返回...\\n\"); getchar(); close(s); exit(-1); } if(strcmp(buf,\"OK\")!=0) { printf(\"用户名不存在或密码错误!请按任意键返回并重新输入!\\n\"); close(s); getchar(); } else { t=0; close(s); } } while(m) { system(\"clear\"); printf(\"\\ ---------- 现金交费----------\\n\"); printf(\"登录成功!用户:%s。\(输入'exit'返回主菜单)\\n\\n\",oprname); printf(\"请输入手机号码:\"); scanf(\"%s\",&phoneno); if(strcmp(phoneno,\"exit\")==0) break; if((sp=getservbyname(service,\"tcp\"))==NULL){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); exit(-1); } if((hp=gethostbyname(dest))==0){ fprintf(stderr,\"接服务器会话出错!请稍后再试!\\n\"); exit(-1); } 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,\"服务器会话出错!请稍后再试!\\n\"); 18 \"); exit(-1); } if(connect(s,(struct sockaddr*)&sin,sizeof(sin))==-1){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); close(s); exit(-1); } sprintf(buf,\"phoneSer-1-%s\",phoneno); if(write(s,buf,rec_length)!=rec_length){ //to server fprintf(stderr,\"Write Socket s ERROR!\\n\"); fprintf(stderr,\"请按任意键返回...\"); getchar(); close(s); exit(-1); } if(read(s,buf,rec_length)==0){ //get replay from server fprintf(stderr,\"Read Socket s Error!\\n\"); fprintf(stderr,\"请按任意键返回...\"); getchar(); close(s); exit(-1); } strsplit(buf,v,d); if(strcmp(v[0],\"OK\")!=0) { printf(\"手机号码不存在或输入错误!请按任意键返回并重新输入! close(s); getchar(); getchar(); } else { close(s); while(r) { printf(\"要继续吗?(y|n):\",v[1]); scanf(\"%s\",ch); if(strcmp(ch,\"y\")==0||strcmp(ch,\"Y\")==0) { printf(\"请输入交费金额:\"); scanf(\"%s\",&money); if((sp=getservbyname(service,\"tcp\"))==NULL){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); 19 exit(-1); } if((hp=gethostbyname(dest))==0){ fprintf(stderr,\"接服务器会话出错!请稍后再试!\\n\"); exit(-1); } 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,\"服务器会话出错!请稍后再试!\\n\"); exit(-1); } if(connect(s,(struct sockaddr*)&sin,sizeof(sin))==-1){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); close(s); exit(-1); } sprintf(connbuf,\"phoneSer-2-%s-%s-%s\",phoneno,money,oprname); if(write(s,connbuf,rec_length)!=rec_length){ //to server fprintf(stderr,\"Write Socket s ERROR!\\n\"); fprintf(stderr,\"请按任意键返回...\"); getchar(); close(s); break; } if(read(s,connbuf,rec_length)==0){ //get replay from server fprintf(stderr,\"Read Socket s Error\\n\"); fprintf(stderr,\"请按任意键返回...\\n\"); getchar(); close(s); break; } close(s); printf(connbuf); if(strcmp(connbuf,\"OK\")==0) { float xx; 20 xx=atof(money); printf(\"您已成功交费!\\n\"); printf(\"交费回执单:\\n\"); printf(\"*****************\\n\"); printf(\"机主:%s\号码:%s\金额:%-10.2f\用户:%s\\n\",v[1],phoneno,xx,oprname); printf(\"*****************\\n\"); m=0; getchar(); getchar(); break; } else { printf(\"交费失败!\\n\"); scanf(\"%s\",tmp); break; } } else if(strcmp(ch,\"n\")==0||strcmp(ch,\"N\")==0) break; else { printf(\"输入错误!请按任意键重新输入(y或n)。\\n\"); getchar(); } } } } close(s);break; case'2': while(n) { system(\"clear\"); printf(\"\\ ---------- 网上交费----------\\n\"); printf(\"\\n请输入手机号码:\"); scanf(\"%s\",&usrname); if(strcmp(phoneno,\"exit\")==0) break; getchar(); set_disp_mode(STDIN_FILENO,0); getpasswd(usrpwd,sizeof(usrpwd)); set_disp_mode(STDIN_FILENO,1); if((sp=getservbyname(service,\"tcp\"))==NULL){ 21 入...\\n\"); fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); exit(-1); } if((hp=gethostbyname(dest))==0){ fprintf(stderr,\"接服务器会话出错!请稍后再试!\\n\"); exit(-1); } 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,\"服务器会话出错!请稍后再试!\\n\"); exit(-1); } if(connect(s,(struct sockaddr*)&sin,sizeof(sin))==-1){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); close(s); exit(-1); } sprintf(connbuf,\"phoneSer-3-%s-%s\",usrname,usrpwd); if(write(s,connbuf,rec_length)!=rec_length){ //to server fprintf(stderr,\"Write Socket s ERROR!\\n\"); fprintf(stderr,\"按任意键返回...\\n\"); getchar(); close(s); exit(-1); } if(read(s,connbuf,rec_length)==0){ //get replay from server fprintf(stderr,\"Read Socket s Error\\n\"); fprintf(stderr,\"按任意键返回...\\n\"); getchar(); close(s); exit(-1); } close(s); if(strcmp(connbuf,\"failed\")==0) { printf(\"手机号不存在或密码错误!请按任意键返回并重新输 getchar(); } else { 22 while(q) { printf(\"请输入交费号码:\"); scanf(\"%s\",&phoneno); printf(\"请输入交费金额:\"); scanf(\"%s\",&money); while(z) { printf(\"请输入银行卡号(或exit返回):\"); scanf(\"%s\",&bankno); if(strcmp(bankno,\"exit\")==0) break; getchar(); set_disp_mode(STDIN_FILENO,0); getpasswd(bankpwd,sizeof(bankpwd)); set_disp_mode(STDIN_FILENO,1); if((sp=getservbyname(service,\"tcp\"))==NULL){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); exit(-1); } if((hp=gethostbyname(dest))==0){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); exit(-1); } 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,\"服务器会话出错!请稍后再试!\\n\"); exit(-1); } if(connect(s,(struct sockaddr*)&sin,sizeof(sin))==-1){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); close(s); exit(-1); } sprintf(quebuf,\"bankSer-0-%s-%s\",bankno,bankpwd); if(write(s,quebuf,rec_length)!=rec_length){ //to server fprintf(stderr,\"Write Socket s ERROR!\\n\"); fprintf(stderr,\"请按任意键返回...\\n\"); getchar(); 23 close(s); break; } if(read(s,quebuf,rec_length)==0){ //get replay from server fprintf(stderr,\"Read Socket s Error!\\n\"); fprintf(stderr,\"请按任意键返回...\\n\"); getchar(); close(s); break; } close(s); if(strcmp(quebuf,\"failed\")==0) { printf(\"银行卡不存在或密码错误!请重新输入。\\n\"); getchar(); } else { if((sp=getservbyname(service,\"tcp\"))==NULL){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); exit(-1); } if((hp=gethostbyname(dest))==0){ fprintf(stderr,\"接服务器会话出错!请稍后再试!\\n\"); exit(-1); } 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,\"服务器会话出错!请稍后再试!\\n\"); exit(-1); } if(connect(s,(struct sockaddr*)&sin,sizeof(sin))==-1){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); close(s); exit(-1); 24 } sprintf(quebuf,\"both-%s-%s-%s-%s\",bankno,phoneno,money,usrname); if(write(s,quebuf,rec_length)!=rec_length){ //to server from server fprintf(stderr,\"Write Socket s ERROR!\\n\"); fprintf(stderr,\"请按任意键返回...\\n\"); getchar(); close(s); break; } if(read(s,quebuf,rec_length)==0){ //get replay fprintf(stderr,\"Read Socket s Error\\n\"); fprintf(stderr,\"请按任意键返回...\\n\"); getchar(); close(s); break; } close(s); if(strcmp(quebuf,\"overdraft\")==0) { printf(\"银行卡余额不足!\\n\"); printf(\"按任意键换用其它卡号。\\n\"); close(s); getchar(); getchar(); exit(0); } else if(strcmp(quebuf,\"OK\")==0) { printf(\"交费成功!\\n\"); printf(\"按任意键退出...\"); close(s); getchar(); getchar(); exit(0);break; } else if(strcmp(quebuf,\"overbackfailed\")==0) { printf(\"交费失败!银行数据出错!\"); close(s); getchar(); getchar(); 25 break; } else { printf(\"交费失败!\\n\"); printf(\"按任意键返回...\"); close(s); getchar(); break; } } } } close(s); break; } } case '3': while(n) { system(\"clear\"); printf(\"\\ ---------- 查询----------\\n\"); printf(\"\\n请输入手机号码:\"); scanf(\"%s\",&usrname); if(strcmp(phoneno,\"exit\")==0) break; getchar(); set_disp_mode(STDIN_FILENO,0); getpasswd(usrpwd,sizeof(usrpwd)); set_disp_mode(STDIN_FILENO,1); if((sp=getservbyname(service,\"tcp\"))==NULL){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); exit(-1); } if((hp=gethostbyname(dest))==0){ fprintf(stderr,\"接服务器会话出错!请稍后再试!\\n\"); exit(-1); } 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,\"服务器会话出错!请稍后再试!\\n\"); 26 入...\\n\"); exit(-1); } if(connect(s,(struct sockaddr*)&sin,sizeof(sin))==-1){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); close(s); exit(-1); } sprintf(connbuf,\"phoneSer-3-%s-%s\",usrname,usrpwd); if(write(s,connbuf,rec_length)!=rec_length){ //to server fprintf(stderr,\"Write Socket s ERROR!\\n\"); fprintf(stderr,\"按任意键返回...\\n\"); getchar(); close(s); exit(-1); } if(read(s,connbuf,rec_length)==0){ //get replay from server fprintf(stderr,\"Read Socket s Error\\n\"); fprintf(stderr,\"按任意键返回...\\n\"); getchar(); close(s); exit(-1); } close(s); if(strcmp(connbuf,\"failed\")==0) { printf(\"手机号不存在或密码错误!请按任意键返回并重新输 getchar(); } else { strsplit(connbuf,v,d); while(x) { if((sp=getservbyname(service,\"tcp\"))==NULL){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); exit(-1); } if((hp=gethostbyname(dest))==0){ fprintf(stderr,\"接服务器会话出错!请稍后再试!\\n\"); exit(-1); } bzero(&sin,sizeof(sin)); bcopy(hp->h_addr,&sin.sin_addr,hp->h_length); 27 sin.sin_family=hp->h_addrtype; sin.sin_port=sp->s_port; if((s=socket(AF_INET,SOCK_STREAM,0))==-1){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); exit(-1); } if(connect(s,(struct sockaddr*)&sin,sizeof(sin))==-1){ fprintf(stderr,\"服务器会话出错!请稍后再试!\\n\"); close(s); exit(-1); } sprintf(readbuf,\"phoneSer-1-%s\",usrname); if(write(s,readbuf,rec_length)!=rec_length){ //to server fprintf(stderr,\"Write Socket s ERROR!\\n\"); printf(\"按任意键返回...\"); getchar(); close(s); break; } if(read(s,readbuf,rec_length)==0){ //get replay from server fprintf(stderr,\"Read Socket is Error!\\n\"); printf(\"按任意键返回...\"); getchar(); close(s); break; } if(strcmp(readbuf,\"failed\")==0) { printf(\"查询出错!\\n\"); printf(\"按任意键返回...\"); getchar(); close(s); break; } else{ strsplit(readbuf,v,d); printf(\"号码:%s\\余额:%-10.2f\\n\",usrname,atof(v[2])); printf(\"按任意键继续...\"); close(s); getchar(); getchar(); break; 28 } close(s); break; } close(s); break; } } case '4': k=0; printf(\"谢谢使用!\\n\"); close(s); getchar();break; default: printf(\"输入错误!请重新输入!\\n\"); close(s); getchar(); } } } //函数set_disp_mode用于控制是否开启输入回显功能 //如果option为,则关闭回显,为则打开回显 int set_disp_mode(int fd,int option) { int err; struct termios term; if(tcgetattr(fd,&term)==-1){ perror(\"Cannot get the attribution of the terminal\"); return 1; } if(option) term.c_lflag|=ECHOFLAGS; else term.c_lflag &=~ECHOFLAGS; err=tcsetattr(fd,TCSAFLUSH,&term); if(err==-1 && err==EINTR){ perror(\"Cannot set the attribution of the terminal\"); return 1; } return 0; } //函数getpasswd用于获得用户输入的密码,并将其存储在指定的字符数组中 29 int getpasswd(char* passwd, int size) { int c; int n = 0; printf(\"请输入密码:\"); do{ c=getchar(); if (c != '\\n'&&c!='\\r'){ passwd[n++] = c; } }while(c != '\\n' && c !='\\r' && n < (size - 1)); passwd[n] = '\\0'; printf(\"\\n\"); return n; } void strsplit(char *sourceStr,char **v,char d) { int i,j,l; j=0;v[j]=sourceStr; l=strlen(sourceStr); for(i=0;i *(sourceStr+i)='\\0'; v[++j]=sourceStr+i+1; } } } 银行服务器 #include #include 30 #define rec_length 80 void strsplit(char *sourceStr,char **v,char d); main(int argc, char **argv ) { struct sockaddr_in sin; struct servent *sp; int s,ns,pid; float money; static int fd; char buf[50],quebuf[80]; char *service; char d='-',**v=(char**)malloc(sizeof(char*) * 10); MYSQL mysql; MYSQL_ROW row; MYSQL_RES *result; if(argc!=1) service=argv[1]; else { fprintf(stderr,\"NO service assigned!\\nUsage:\\n\"); fprintf(stderr,\"\%s server_name!\\n\",argv[0]); fprintf(stderr,\"Note: server_name is defined in file /etc/services\\n\"); exit(-1); } if(mysql_init(&mysql)==NULL){ fprintf(stderr,\"Error: in init database!\\n\"); exit(-1); } if(!mysql_real_connect(&mysql,\"localhost\",\"root\",0,\"bankSer\",0,NULL,0)){ fprintf(stderr,\"Error in connection: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); mysql_close(&mysql); exit(-1); } if((sp=getservbyname(service,\"tcp\"))==NULL){ fprintf(stderr,\"Error: in getservbyname!\\n\"); exit(-1); } if((s=socket(AF_INET,SOCK_STREAM,0))==-1){ fprintf(stderr,\"Error: in socket create!\\n\"); exit(-1); } bzero(&sin,sizeof(sin)); 31 sin.sin_port=sp->s_port; if(bind(s,(struct sockaddr*)&sin,sizeof(sin))==-1){ fprintf(stderr,\"Error: in bind!\\n\"); close(s); exit(-1); } if(listen(s,10)==-1){ fprintf(stderr,\"Error: in listen!\\n\"); close(s); exit(-1); } while(1) { fprintf(stderr,\"\\n\\ ----- 银行服务器已启动!-----\\n\"); fprintf(stderr,\"\\n\\ *****************************\\n\ 请稍后...\\n\"); if((ns=accept(s,0,0))==-1){ // wait a connection */ fprintf(stderr,\"Error: in accept!\\n\"); continue; } if((pid=fork())==-1){ // conneted, and then create child proc fprintf(stderr,\"Error: server in create child process!\\n\"); close(s); exit(-1); } if(pid!=0){ //parent proce, nothing to do, and to the next loop close(ns);wait(0); continue; } if(pid==0) { fprintf(stderr,\"\\n\\ -----银行服务器已启动!-----\\n\"); printf(\"\\n\\ **********************************\\n\\正在使用中……\"); if(read(ns,buf,rec_length)==0){ fprintf(stderr,\"Read nothing from socket:ns!\\n\"); close(ns); exit(-1); } strsplit(buf,v,d); if(strcmp(v[0],\"0\")==0)//传送信息的格式:-num-pwd { sprintf(quebuf,\"select * from user_info where num=\\\"%s\\\"\",v[1]); if(mysql_query(&mysql,quebuf)!=0){ fprintf(stderr,\"Error in query user info: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); mysql_close(&mysql); exit(-1); } 32 if((result=mysql_store_result(&mysql))==NULL){ fprintf(stderr,\"Error in store_result: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); mysql_free_result(result); mysql_close(&mysql); exit(-1); } if((mysql_num_rows(result))==0){ if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } else row=mysql_fetch_row(result); if(strcmp(v[1],row[0])==0&&strcmp(v[2],row[1])==0) { if(write(ns,\"OK\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } else { if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } close(ns); } else if(strcmp(v[0],\"1\")==0)//传送信息的格式:-num-money { sprintf(quebuf,\"select * from user_info where num=\\\"%s\\\"\",v[1]); if(mysql_query(&mysql,quebuf)!=0){ fprintf(stderr,\"Error in query user info: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); getchar(); mysql_close(&mysql); exit(-1); } if((result=mysql_store_result(&mysql))==NULL){ fprintf(stderr,\"Error in store_result: %s 33 [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); getchar(); mysql_free_result(result); mysql_close(&mysql); exit(-1); } if((mysql_num_rows(result))==0){ if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); getchar(); close(ns); exit(-1); } } else row=mysql_fetch_row(result); money=atof(row[2])-atof(v[2]); if(money>=0) { sprintf(quebuf,\"update user_info set deposit=%f where num=\\\"%s\\\"\",money,row[0]); if(mysql_query(&mysql,quebuf)!=0){ fprintf(stderr,\"Error in query: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); mysql_close(&mysql); write(ns,\"failed\",rec_length); exit(-1); } else { if(write(ns,\"OK\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } } else { if(write(ns,\"overdraft\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } 34 } close(ns); } else if(strcmp(v[0],\"2\")==0)//交费失败,数据回滚-num-money { sprintf(quebuf,\"update user_info set deposit=deposit+%d where num=\\\"%s\\\"\",v[2],v[1]); if(mysql_query(&mysql,quebuf)!=0){ fprintf(stderr,\"Error in query: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); mysql_close(&mysql); write(ns,\"failed\",rec_length); exit(-1); } else { if(write(ns,\"OK\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } close(ns); } else { fprintf(stderr,\"出现未知错误!\"); close(ns); exit(-1); } close(ns); } } } void strsplit(char *sourceStr,char **v,char d) { int i,j,l; j=0;v[j]=sourceStr; l=strlen(sourceStr); for(i=0;i *(sourceStr+i)='\\0'; 35 v[++j]=sourceStr+i+1; } } } 手机服务器 #include #include void strsplit(char *sourceStr,char **v,char d); main(int argc, char **argv ) { struct sockaddr_in sin; struct servent *sp; int s,ns,pid; float money; static int fd; char buf[50],quebuf[50]; char *service; char d='-',**v=(char**)malloc(sizeof(char*) * 10); MYSQL mysql; MYSQL_ROW row; MYSQL_RES *result; if(argc!=1) service=argv[1]; else { fprintf(stderr,\"NO service assigned!\\nUsage:\\n\"); fprintf(stderr,\"\%s server_name!\\n\",argv[0]); fprintf(stderr,\"Note: server_name is defined in file /etc/services\\n\"); exit(-1); } 36 if(mysql_init(&mysql)==NULL){ fprintf(stderr,\"Error in init database!\\n\"); exit(-1); } if(!mysql_real_connect(&mysql,\"localhost\",\"root\",0,\"phoneSer\",0,NULL,0)){ fprintf(stderr,\"Error in connection database: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); mysql_close(&mysql); exit(-1); } if((sp=getservbyname(service,\"tcp\"))==NULL){ fprintf(stderr,\"Error: in getservbyname\\n\"); exit(-1); } if((s=socket(AF_INET,SOCK_STREAM,0))==-1){ fprintf(stderr,\"Error: socket create!\\n\"); exit(-1); } bzero(&sin,sizeof(sin));//置字节字符串的前sizeof(sin)个字节为零 sin.sin_port=sp->s_port; if(bind(s,(struct sockaddr*)&sin,sizeof(sin))==-1){ fprintf(stderr,\"Error: in bind!\\n\"); close(s); exit(-1); } if(listen(s,10)==-1){ fprintf(stderr,\"Error: in listen!\\n\"); close(s); exit(-1); } while(1) { fprintf(stderr,\"\\n\\ ----- 欢迎使用手机话费缴费系统!-----\\n\"); fprintf(stderr,\"\\n\\ ***************************************\\n\\ 请稍后...\\n\"); if((ns=accept(s,0,0))==-1){ // wait a connection */ fprintf(stderr,\"Error: in accept!\\n\"); continue; } if((pid=fork())==-1){ // conneted, and then create child proc fprintf(stderr,\"Error: server in create child process!\\n\"); close(s); exit(-1); } if(pid!=0){ //parent proce, nothing to do, and to the next loop 37 close(s);//testing close(ns); wait(0); continue; } if(pid==0) { fprintf(stderr,\"\\n\\ ----- 欢迎使用手机话费缴费系统!-----\\n\"); printf(\"\\n\\ **********************************************\\n\\正在使用中...\"); /* if((fd=open(phone.log,O_WRONLY|O_CREAT|O_APPEND,0644))==-1){ fprintf(stderr,\"phone.Log file %s open error!\\a\\n\"); exit(-1); } */ if(read(ns,buf,rec_length)==0){ fprintf(stderr,\"Read nothing from socket:ns!\\n\"); close(ns); exit(-1); } strsplit(buf,v,d); if(strcmp(v[0],\"0\")==0)//0-oprName-oprPwd { sprintf(quebuf,\"select * from opr_list where oprName=\\\"%s\\\"\",v[1]); if(mysql_query(&mysql,quebuf)!=0){ fprintf(stderr,\"Error: in query operator info: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); mysql_close(&mysql); exit(-1); } if((result=mysql_store_result(&mysql))==NULL){ fprintf(stderr,\"Error: in store_result: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); mysql_free_result(result); mysql_close(&mysql); exit(-1); } if((mysql_num_rows(result))==0){ if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } else 38 row=mysql_fetch_row(result); if(strcmp(v[1],row[0])==0&&strcmp(v[2],row[1])==0) { if(write(ns,\"OK\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } else { if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } close(ns); } if(strcmp(v[0],\"1\")==0)//1-phoneNo { sprintf(quebuf,\"select * from usr_list where phoneNo=\\\"%s\\\"\",v[1]); if(mysql_query(&mysql,quebuf)!=0){ fprintf(stderr,\"Error in query user info: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); mysql_close(&mysql); exit(-1); } if((result=mysql_store_result(&mysql))==NULL){ fprintf(stderr,\"Error in store_result: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); mysql_free_result(result); mysql_close(&mysql); exit(-1); } if((mysql_num_rows(result))==0){ if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } else row=mysql_fetch_row(result); if(strcmp(v[1],row[0])==0) 39 { sprintf(buf,\"OK-%s-%s\",row[1],row[3]);//返回机主姓名和余额 if(write(ns,buf,rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } else { if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } close(ns); } if(strcmp(v[0],\"2\")==0)//2-phoneNo-money-操作员或交费号 { money=atof(v[2]); sprintf(quebuf,\"update usr_list set money=money+%f where phoneno=\\\"%s\\\"\",money,v[1]); if(mysql_query(&mysql,quebuf)!=0){ fprintf(stderr,\"Error in query: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); mysql_close(&mysql); write(ns,\"failed\",rec_length); exit(-1); } else { if(write(ns,\"OK\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } close(ns); } if(strcmp(v[0],\"3\")==0)//3-phoneNo-password { printf(\"len=%d\",strlen(v[1])); sprintf(quebuf,\"select * from usr_list where 40 phoneNo=\\\"%s\\\"\",v[1]); if(mysql_query(&mysql,quebuf)!=0){ fprintf(stderr,\"Error in query userinfo: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); getchar(); mysql_close(&mysql); exit(-1); } if((result=mysql_store_result(&mysql))==NULL){ fprintf(stderr,\"Error in store_result: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); getchar(); mysql_free_result(result); mysql_close(&mysql); exit(-1); } if((mysql_num_rows(result))==0){ if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); getchar(); close(ns); exit(-1); } } else row=mysql_fetch_row(result); if(strcmp(v[1],row[0])==0&&strcmp(v[2],row[2])==0) { sprintf(quebuf,\"OK-%s\",row[1]);//返回机主姓名 if(write(ns,quebuf,rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } else { if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } close(ns); } } 41 } } void strsplit(char *sourceStr,char **v,char d) { int i,j,l; j=0;v[j]=sourceStr; l=strlen(sourceStr); for(i=0;i *(sourceStr+i)='\\0'; v[++j]=sourceStr+i+1; } } } 中间件 #include #include void strsplit(char *sourceStr,char **v,char d); main(int argc, char **argv ) { MYSQL mysql; MYSQL_ROW row; MYSQL_RES *result; char d='-',**v=(char**)malloc(sizeof(char*) * 10); struct sockaddr_in client_addr; int length; struct hostent *hpphone; 42 struct sockaddr_in sinphone; struct servent *spphone; char phonebuf[100]; int sphone,pid,spid; char *phoneser,*phonedest; struct hostent *hpbank; struct sockaddr_in sinbank; struct servent *spbank; char bankbuf[100],bankbuf1[100]; int sbank; char *bankser,*bankdest; char *sdest; struct sockaddr_in sin; struct servent *sp; int s,ns; char buf[100]; char *service; char connbuf[100]; // test the environment parameter: lservice, dservice, server_name if(argc==2){ service=argv[1];} else { fprintf(stderr,\"Parameter assigned Error!\\nUsage:\\n\"); fprintf(stderr,\"\%s lservice d server_name!\\n\",argv[0]); fprintf(stderr,\"Note: server_name is defined in file /etc/hosts\\n\"); fprintf(stderr,\"and: lservice dservice are defined in file /etc/services\\n\"); exit(-1); } if(mysql_init(&mysql)==NULL){ fprintf(stderr,\"Error in init database!\\n\"); exit(-1); } if(!mysql_real_connect(&mysql,\"localhost\",\"root\",0,\"middle\",0,NULL,0)){ fprintf(stderr,\"Error in connection database: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); mysql_close(&mysql); exit(-1); } if((sp=getservbyname(service,\"tcp\"))==NULL){ fprintf(stderr,\"Error: in getservbyname!\\n\"); exit(-1); } 43 if((s=socket(AF_INET,SOCK_STREAM,0))==-1){ fprintf(stderr,\"Error: in socket create!\\n\"); exit(-1); } bzero(&sin,sizeof(sin)); sin.sin_port=sp->s_port; if(bind(s,(struct sockaddr*)&sin,sizeof(sin))==-1){ fprintf(stderr,\"Error: in bind!\\n\"); close(s); exit(-1); } if(listen(s,10)==-1){ fprintf(stderr,\"Error: in listen!\\n\"); close(s); exit(-1); } while(1) { fprintf(stderr,\"\\n\\ -----中间件已启动!-----\\n\"); fprintf(stderr,\"\\n\\ ****************************\\n\\ 请稍后...\\n\"); bzero(&client_addr,sizeof(struct sockaddr_in)); length=sizeof(struct sockaddr_in); if((ns=accept(s,(struct sockaddr *)(&client_addr),&length))==-1) { fprintf(stderr,\"Error: in accept!\"); continue; } if((pid=fork())==-1){ // conneted, and then create child proc fprintf(stderr,\"Error:in server create child process!\"); close(s); break; } if(pid!=0){ //parent proce, nothing to do, and to the next loop close(ns);wait(0); continue; } if(pid==0) { fprintf(stderr,\"\\n\\ -----中间件已成功启动!-----\\n\"); fprintf(stderr,\"\\n\\ ****************************\\n\\ 请稍后…\"); if(read(ns,buf,rec_length)==0){ fprintf(stderr,\"Read nothing from socket:ns\\n\"); close(ns); exit(-1); } 44 strsplit(buf,v,d); if(strcmp(v[0],\"both\")!=0) { sprintf(connbuf,\"select * from connInfo where service=\\\"%s\\\"\",v[0]); if(mysql_query(&mysql,connbuf)!=0) { fprintf(stderr,\"Error in query serrver info: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); mysql_close(&mysql); exit(-1); } if((result=mysql_store_result(&mysql))==NULL){ fprintf(stderr,\"Error in store_result: %s [%d]\\n\",mysql_error(&mysql),mysql_errno(&mysql)); mysql_free_result(result); mysql_close(&mysql); exit(-1); } else row=mysql_fetch_row(result); if(strcmp(v[0],\"phoneSer\")==0) { phoneser=row[0]; phonedest=\"localhost\"; } else { bankser=row[0]; bankdest=\"localhost\"; } } else { phoneser=\"phoneSer\"; bankser=\"bankSer\"; phonedest=bankdest=\"localhost\"; } if(strcmp(v[0],\"phoneSer\")==0) { if((spphone=getservbyname(phoneser,\"tcp\"))==NULL){ fprintf(stderr,\"Error: in getservbyname phoneSer!\\n\"); exit(-1); } if((hpphone=gethostbyname(phonedest))==0){ 45 fprintf(stderr,\"Error: gethostbyname phoneSer!\\n\"); exit(-1); } bzero(&sinphone,sizeof(sinphone)); bcopy(hpphone->h_addr,&sinphone.sin_addr,hpphone->h_length); sinphone.sin_family=hpphone->h_addrtype; sinphone.sin_port=spphone->s_port; if((sphone=socket(AF_INET,SOCK_STREAM,0))==-1){ fprintf(stderr,\"Error: in socket phoneSer!\\n\"); exit(-1); } if(connect(sphone,(struct sockaddr*)&sinphone,sizeof(sinphone))==-1){ fprintf(stderr,\"Error: in connect phoneSer!\\n\"); close(sphone); exit(-1); } if(strcmp(v[1],\"0\")==0)//phoneSer-0-oprname-oprpwd { sprintf(phonebuf,\"0-%s-%s\",v[2],v[3]); if(write(sphone,phonebuf,rec_length)!=rec_length){ fprintf(stderr,\"Write Socket phoneSer ERROR!\\n\"); close(sphone); exit(-1); } if(read(sphone,phonebuf,rec_length)==0){ //from server fprintf(stderr,\"Read Socket phoneSer Error!\\n\"); close(sphone); exit(-1); } if(strcmp(phonebuf,\"OK\")==0) { if(write(ns,\"OK\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } else { if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } close(sphone); } if(strcmp(v[1],\"1\")==0)//phoneSer-1-phoneNo 46 { sprintf(phonebuf,\"1-%s\",v[2]); if(write(sphone,phonebuf,rec_length)!=rec_length){ fprintf(stderr,\"Write Socket phoneSer ERROR!\\n\"); close(sphone); exit(-1); } if(read(sphone,phonebuf,rec_length)==0){ fprintf(stderr,\"Read Socket phoneSer Error!\\n\"); close(sphone); exit(-1); } if(strcmp(phonebuf,\"failed\")!=0) { if(write(ns,phonebuf,rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } else { if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } close(sphone); } if(strcmp(v[1],\"2\")==0)//phoneSer-2-phoneNo-money-operator { sprintf(phonebuf,\"2-%s-%s-%s\",v[2],v[3],v[4]); if(write(sphone,phonebuf,rec_length)!=rec_length){ fprintf(stderr,\"Write Socket phoneSer ERROR!\\n\"); close(sphone); exit(-1); } if(read(sphone,phonebuf,rec_length)==0){ fprintf(stderr,\"Read Socket phoneSer Error!\\n\"); close(sphone); exit(-1); } if(strcmp(phonebuf,\"OK\")==0) { if(write(ns,\"OK\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } 47 else { if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } close(sphone); } if(strcmp(v[1],\"3\")==0)//phoneSer-3-phoneNo-phonePwd { sprintf(phonebuf,\"3-%s-%s\",v[2],v[3]); if(write(sphone,phonebuf,rec_length)!=rec_length){ fprintf(stderr,\"Write Socket phoneSer ERROR!\\n\"); close(sphone); exit(-1); } if(read(sphone,phonebuf,rec_length)==0){ fprintf(stderr,\"Read Socket phoneSer Error!\\n\"); close(sphone); exit(-1); } if(strcmp(phonebuf,\"failed\")!=0) { if(write(ns,phonebuf,rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } else { if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } close(sphone); } } if(strcmp(v[0],\"bankSer\")==0)//connect to bankSer { if((spbank=getservbyname(bankser,\"tcp\"))==NULL){ fprintf(stderr,\"Error: in getservbyname bankSer!\\n\"); exit(-1); } if((hpbank=gethostbyname(bankdest))==0){ 48 fprintf(stderr,\"Error: in gethostbyname bankSer!\\n\"); exit(-1); } bzero(&sinbank,sizeof(sinbank)); bcopy(hpbank->h_addr,&sinbank.sin_addr,hpbank->h_length); sinbank.sin_family=hpbank->h_addrtype; sinbank.sin_port=spbank->s_port; if((sbank=socket(AF_INET,SOCK_STREAM,0))==-1){ fprintf(stderr,\"Error: in socket bankSer!\\n\"); exit(-1); } if(connect(sbank,(struct sockaddr*)&sinbank,sizeof(sinbank))==-1){ fprintf(stderr,\"Error: in connect bankSer!\\n\"); close(sbank); exit(-1); } if(strcmp(v[1],\"0\")==0)//bankSer-0-num-pwd { sprintf(bankbuf,\"0-%s-%s\",v[2],v[3]); if(write(sbank,bankbuf,rec_length)!=rec_length){ fprintf(stderr,\"Write Socket bankSer ERROR!\\n\"); close(sbank); exit(-1); } if(read(sbank,bankbuf,rec_length)==0){ //from server fprintf(stderr,\"Read Socket bankSer Error!\\n\"); close(sbank); exit(-1); } close(sbank); if(strcmp(bankbuf,\"OK\")==0) { if(write(ns,\"OK\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } else { if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } } close(sbank); } 49 } if(strcmp(v[0],\"both\")==0)//both-bankNo-phoneNo-money-交费号 { if((spbank=getservbyname(bankser,\"tcp\"))==NULL){ fprintf(stderr,\"Error: in getservbyname bankSer!\\n\"); exit(-1); } if((hpbank=gethostbyname(bankdest))==0){ fprintf(stderr,\"Error: in gethostbyname bankSer!\\n\"); exit(-1); } bzero(&sinbank,sizeof(sinbank)); bcopy(hpbank->h_addr,&sinbank.sin_addr,hpbank->h_length); sinbank.sin_family=hpbank->h_addrtype; sinbank.sin_port=spbank->s_port; if((sbank=socket(AF_INET,SOCK_STREAM,0))==-1){ fprintf(stderr,\"Error: in socket bankSer!\\n\"); exit(-1); } if(connect(sbank,(struct sockaddr*)&sinbank,sizeof(sinbank))==-1){ fprintf(stderr,\"Error: in connect bankSer!\\n\"); close(sbank); exit(-1); } sprintf(bankbuf1,\"1-%s-%s\",v[1],v[3]);//1-bankNo-money if(write(sbank,bankbuf1,rec_length)!=rec_length){ fprintf(stderr,\"Write Socket bankSer ERROR!\\n\"); getchar(); close(sbank); exit(-1); } if(read(sbank,bankbuf1,rec_length)==0){ fprintf(stderr,\"Read Socket bankSer Error!\\n\"); getchar(); close(sbank); exit(-1); } close(sbank); if(strcmp(bankbuf1,\"overdraft\")==0) { if(write(ns,\"overdraft\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } close(ns); 50 } if(strcmp(bankbuf1,\"OK\")==0)//bankno,phoneno,money,usrname { if((spphone=getservbyname(phoneser,\"tcp\"))==NULL){ fprintf(stderr,\"Error: in getservbyname phoneSer!\\n\"); exit(-1); } if((hpphone=gethostbyname(phonedest))==0){ fprintf(stderr,\"Error: gethostbyname phoneSer!\\n\"); exit(-1); } bzero(&sinphone,sizeof(sinphone)); bcopy(hpphone->h_addr,&sinphone.sin_addr,hpphone->h_length); sinphone.sin_family=hpphone->h_addrtype; sinphone.sin_port=spphone->s_port; if((sphone=socket(AF_INET,SOCK_STREAM,0))==-1){ fprintf(stderr,\"Error: in socket phoneSer!\\n\"); exit(-1); } if(connect(sphone,(struct sockaddr*)&sinphone,sizeof(sinphone))==-1){ fprintf(stderr,\"Error: in connect phoneSer!\\n\"); close(sphone); exit(-1); } sprintf(phonebuf,\"2-%s-%s-%s\",v[2],v[3],v[4]);//2-phoneNo-money-交费号 if(write(sphone,phonebuf,rec_length)!=rec_length){ fprintf(stderr,\"Write Socket phoneSer(both) ERROR!\\n\"); close(sphone); exit(-1); } if(read(sphone,phonebuf,rec_length)==0){ fprintf(stderr,\"Read Socket phoneSer(both) Error!\\n\"); close(sphone); exit(-1); } close(sphone); if(strcmp(phonebuf,\"failed\")!=0) { if(write(ns,\"OK\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns error!\\n\"); close(ns); exit(-1); } close(ns); } 51 else { if((spbank=getservbyname(bankser,\"tcp\"))==NULL){ fprintf(stderr,\"Error: in getservbyname bankSer!\\n\"); exit(-1); } if((hpbank=gethostbyname(bankdest))==0){ fprintf(stderr,\"Error: in gethostbyname bankSer!\\n\"); exit(-1); } bzero(&sinbank,sizeof(sinbank)); bcopy(hpbank->h_addr,&sinbank.sin_addr,hpbank->h_length); sinbank.sin_family=hpbank->h_addrtype; sinbank.sin_port=spbank->s_port; if((sbank=socket(AF_INET,SOCK_STREAM,0))==-1){ fprintf(stderr,\"Error: in socket bankSer!\\n\"); exit(-1); } if(connect(sbank,(struct sockaddr*)&sinbank,sizeof(sinbank))==-1){ fprintf(stderr,\"Error: in connect bankSer!\\n\"); close(sbank); exit(-1); } sprintf(bankbuf,\"2-%s-%s\",v[1],v[3]);//失败回滚2-bankNo-money if(write(sbank,bankbuf,rec_length)!=rec_length){ fprintf(stderr,\"Write Socket bankSer(数据回滚时) ERROR!\\n\"); close(sbank); exit(-1); } if(read(sbank,bankbuf,rec_length)==0){ fprintf(stderr,\"Read Socket bankSer(数据回滚时) Error!\\n\"); close(sbank); exit(-1); } close(sbank); if(strcmp(bankbuf,\"OK\")==0) { if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns(数据回滚时) error!\\n\"); 52 close(ns); exit(-1); } } else { if(write(ns,\"overbackfailed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns(数据回滚时) error!\\n\"); close(ns); exit(-1); } } } } else { if(write(ns,\"failed\",rec_length)!=rec_length){ fprintf(stderr,\"Write socket ns(银行直接出错) error!\\n\"); close(ns); exit(-1); } } close(sphone); close(sbank); } }//pid==0 } } void strsplit(char *sourceStr,char **v,char d) { int i,j,l; j=0;v[j]=sourceStr; l=strlen(sourceStr); for(i=0;i *(sourceStr+i)='\\0'; v[++j]=sourceStr+i+1; } } } 53 八、运行结果 1、交费界面 2、查询界面 3、退出界面 54 九、总结,收获与体会 时长两周的操作系统课程设计终于结束了,我和我的小组成员也顺利的完成了我们的设计,在这个过程中我体会到了团结的力量和我对操作系统的一些新的认识。 操作系统是一种程序,有着更高的特权级别,功能是提供服务与管理一些硬件的资源,存储器管理,处理机管理,文件管理,设备管理,我觉得这些问题大多数都可归结为数据结构,用数据结构的角度去解决应当不难,但是在用户程序与系统本身之间的切换方面总是感觉有些问题想不清楚,找不到我一直强调的那种会让问题变得简单的高深理解,我还需要时间去理解,我想听听老师对这方面的认识,说些高度概括的词让我思考。同时我也和别的同学积极交流,共同商讨解决的办法。我深深的体会到,一个人的知识和力量是有限的,只有借助大家共同的力量才能又快又好的解决问题。学过的人都知道,操作系统这门课并不是很好学,也好像缺失趣味性,让人很难专注精力去学习。但是通过这两周的课程设计,我不仅发现了我知识的不足还发现了其实操作系统并不是一点趣味都没有。 现将课程设计中的收获简单的写在下面。 1.程序的设计思想的精巧的重要性,是不管怎么说都不为过的,好的设计可以让大家很快的明白你的思想,而且很方便的来实现它。 2.在多人做项目的时候,队员的交流是非常重要的,接口的说明和思想的交流都是很关键的部分。 3.良好的编程习惯,它可以使你的程序很方便的被别人阅读,也很方便的被更改,所以可以的话,尽可能多的写出注释,没有人会闲你写的太多。 4.尽可能多的和客户去联系,因为你写的东西可能并不满足他的要求,而你可能并不知道,或者在你完成了后才发现自己根本没有符合要求,这样简直会让 55 你疯掉。 5.基本的语言功底一定要扎实,不想看到一个cin或者getline会让我们查一个小时资料。 课程设计结束了,但是我们的学习并没有结束,重要的是有了多人合作项目的经验,这才是最重要了。 十、参考文献 《Linux操作系统》 (主编:邵国金 主审:郭玉东 电子工业出版社) 《Linux高级编程》 (主编:Neil Matthew 机械工业出版社) 《计算机操作系统》 (主编:汤子瀛 西安电子科技大学出版社) 《Linux/Unix C编程入门》(主编:贾明 严世贤 人民邮电出版社) 《红帽Linux9 从入门到精通》(主编:江著 邱仲潘等译 电子工业出版社出版) 56 因篇幅问题不能全部显示,请点此查看更多更全内容