手机模拟缴费二(c/m/s)
来源:互联网 发布:金正恩其实很厉害知乎 编辑:程序博客网 时间:2024/06/08 14:06
4.2 接口设计
为了实现系统用户信息的保存机制,根据数据库结构的具体设计,设计数据库接口;由于系统的功能实现要通过网络,依赖于C/M/S工作机制,需要设计套接层接口。
(1) 数据库接口
1) mysql_init(&mysql);//初始化数据结构
2) mysql_real_connect(&mysql,"localhost","root",
NULL,"ser_log",0,NULL,0); //连接数据库
3) mysql_query(&mysql,str);//执行查询语句mysql_query
4) result=mysql_store_result(&mysql); //保存结果
5) while((row=mysql_fetch_row(result))){ //处理结果集
fprintf(stdout,"%s|\t%s\n",row[0],row[2]);
}
善后工作:
6) mysql_free_result(result);//清理数据
7) mysql_close(&mysql);//关闭连接
(2) socket接口
1) 创建套接字:socket()
socket()向应用程序提供创建套接字的手段,其用法如下:
#include <sys/socket.h>
int socket(int domain, int type, intprotocol);
该系统调用使用3个参数,domain为协议族,IPv4时取AF_INET,IPv6时为AF_INET6;type为类型,根据需要可取SOCK_STREAM,SOCK_DGRAM或SOCK_RAW;protocol为协议,一般取0,让系统使用指定类型和协议族上的默认协议。
socket()根据这3个参数建立一个套接字,并将相应的资源分配给它,同时返回一个整型套接字号,它与文件部分系统调用open()的返回值意义相同。因此,把它叫做套按字描述符,以后可以通过该描述符进行网络I/O操作。socket()之后,该套接字符只与一个特定的协议相联系,实际上只指定了相关五元组中的“协议”这一元。
socket()成功时返回套接字描述符,失败时返回-1.
2) 绑定本地地址:bind()
当一个套接字创建之后,还没有被具体化。bind()将本地址(包括本地主机地址和本地端口地址)与新创建的套接字绑定起来,以形成本地半相关。本函数适用于数据报或流类套接口,在connect()或listen()之前调用,其用法为:
int bind(int sockfd,const structsockaddr *my_addr, int addrlen);
参数sockfd为socket()成功时返回的套接字描述符;my_addr为本方地址数据结构指针;addrlen为my_addr所指sockaddr结构的真实长度,一般为sizeof(sockaddr)。
bind()成功时返回0,失败时返回-1,且设置errno。
3) 启用监听:listen()
当一个套接字被创建之后,它被假设为主动的,可以主动发起连接,但作为服务用的套按字必须是被动的。listen()可以将套接字变为被动的,表明它愿意接收连接。1isten()需在bind()之后accept()之前调用,其调用格式如下:
int listen(int sockfd, int backlog);
listen()将套接字sockfd变为被动的,并建立长度为backlog的请求连接队列。backlog定义最大长度的socket等待连接的队列,默认值为5,当等待连接的请求队列长于此值时将被拒绝。
listen()成功时返回0,失败时返回-1,且设置errno。
4) 等待接受连接:accept()
accept()用于使服务器与等待连接的客户建立实际连接,其用法为:
int accept(int sockfd, struct sockaddr*addr,int socklen_t addrlen);
sockfd为socket()返回的描述符;addr是个指向sockaddr型数据结构的指针,是连接建立后内核填入的要求接入方的信息,通过此可以测定哪个地址在哪个端口上呼叫自己。addrlen为addr所指sockaddr型结构的真实大小,通过它可以控制accept不将多余的字节传给addr,通常为sizeof(sockaddr)。
申请建立连接:connect()
在服务器方依次调用listen()和accept()后,就算为提供服务准备好了一切,客户方可在自己调用socket()创建套接字之后,可以调用connect()申请与服务器建立连接了,其用法如下:
int connect(int sockfd,const structsockaddr *server_addr,
int socklen_t addrlen);
sockfd为客户端socket()的返回值;server_addr为所要连接的服务器sockaddr结构,包括了对方IP地址和端口等信息,为连接的目的地;addrlen为server_addr所指sockaddr型结构的真实长度,通常为sizeof(sockaddr)。
5) 数据传输:send()/write与recv()/read()
当建立真正连接后,服务器就可通过accept()产生的新套接字传输数据了。常用的数据发送和接收的系统调用有send()和recv(),用法如下:
int send(int sockfd,void *buf,intlen,int flags);
int recv(int sockfd,void *buf,intlen,int flags);
sockfd为通过accept()和connect()建立的套接字,buf为发送/接收的数据存放位置,len为发送/接收数据的长度。
6) 关闭套接字:close()
当一个套接字使用完毕后也要立即将其关闭以释放系统和网络资源。close()用于关闭套接字并释放分配给该套接字的系统和网络资源,关闭网络连接,其用法为:
int close(int sockfd);
该close()就是文件部分的系统调用close(),它在成功时返回0,失败时返回-1。
4.3 与主机、服务器相关的数据结构及函数
(1) 与主机相关的数据结构及函数
与主机信息相关数据结构为hostent,其定义为
struct hostent {
char *h_name; //Officialname of host
char **h_aliases; //Aliaslist.
int h_addrtype; //Host address type
int h_length; //Length of address
char **h_addr_list; //List of addrs from NS
};
可通过函数gethostbyname()或gethostbyaddr()获得主机的hostent结构信息,它们的用法为:
#include <netdb.h>
struct hostent *gethostbyname(const char*name);
struct hostent *gethostbyaddr(const char*addr,int len,int type);
其中name为主机名,可以是能通过DNS进行解析的官方机名,也可是定义在/etc/hosts中的主机名。addr是一个指向in_addr的结构指针,len指明addr所指字in_addr型变量的长度,type为地址族,对于SCOK_STREAM,type的值为AF_INET。
(2) 与服务器相关的数据结构及函数
与服务器相关的数据结构为servent,其定义如下:
struct servent {
char *s_name; //Officialservice name
char **s_aliases; //Alias list
int s_port; //Port number
char *s_proto; //Protocolto use
};
可以通过函数getservbyname()和getservbyport()获得与某个服务相关的servent结构信息,它们的用法为:
#include <netdb.h>
struct servent *getservbyname(const char*name, const char *protocol);
struct servent *getservbyport(int port,const char *protocol)
其中name为定义在/etc/services的服务名,protocol为所对应的协议,可以为tcp或udp。port为所使用的端口号。
4.4 模块功能说明
1) 网上缴费
用户使用网上缴费功能,首先进行系统登录(若已经注册,则直接登录;若没有注册,则先注册,注册成功后,再登录系统选择服务),输入手机号码和密码,登录成功后,选择缴费功能,输入缴费卡号、密码和充值金额,客户端根据用户提供的信息向中间件发送请求,中间件收到请求后,接受客户端数据,然后发送给服务器,服务器把充值卡号和密码及充值金额对照数据库查询,并返回确认信息,中间件在得到确认信息后,从接受表中检测返回给客户端,并监控错误无返回结果的情况。服务器从接收表中查询到充值信息指令,把充值的具体金额填入数据库,得到“充值费用” 后从主数据库进行处理,并保存银行卡表中相应的余额信息,更新用户基本信息表中的余额。 “服务器处理系统”如果因为错误没有得到结果,把返回结果“系统错误”填入发送错误信息给中间件,然后中间件把信息返回给用户。
2) 信息查询
用户使用查询功能,首先进行系统登录(若已经注册,则直接登录;若没有注册,则先注册,注册成功后,再登录系统选择服务),输入手机号码和密码,登录成功后,可以进行个人账户的相关信息查询,如套餐查询、用户信息查询、消费信息查询等。
1)程序运行主界面
客户端启动后,进入程序运行的主界面,用户根据自己的需求选择不同的功能执行,已注册的用户可以直接登录,进去服务界面,没有注册的用户需进行注册,注册成功后方可登录,选择服务,如图5-6所示。
5.2 windows平台环境
借助MicrosoftVisual Studio 2008运行环境,实现客户端的功能。图5-12所示为用户登录窗体。
编码过程中遇到的问题:
1. 在设计阶段,我们先做了代码设计,而不是数据库设计,导致在一段时间以后我们陷入了迷茫阶段。然后开始设计数据库,突然发现我们的好多的的问题,比如SQL命令已经忘得差不多了。通过看书复习勉强的设计出来现在的数据库。
2. 在编码阶段,在老师给的Linux框架内添加了自己的内容,在数据传输格式上,犯了错,造成了许多不必要的麻烦,还好,在大家的一起努力下,攻破这个小难题。
3. 在整体的功能实现时,我们有各自的见解,我们求同存异的保留系统中的功能,团队是推进发展的基础。
4. 关于这个数据存储上,我们认为应该是密文保存,密文传输,但是由于时间有限这项功能我们无法实现。
5. 我们在windows端客户端设计的时候出现乱码,很是头疼,现在还未解决。
6. 系统在设计之处出现很多明显的漏洞,在我们的不懈努力下,我们完成了初步的功能实现。
7. Linux与windows进程通信出现数据不严格相同我们要继续数据格式的转换。
1)windows端部分源代码using System;using System.Collections.Generic;using System.Collections;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Net;using System.Net.Sockets;using System.Threading;namespace Linux课程设计{ public partial class Form2 : Form { private IPAddress myIP = IPAddress.Parse("192.168.17.128"); private IPEndPoint Myserver; private Socket connectSock; public Form2(){ InitializeComponent(); }private void Form2_Load(object sender, EventArgs e){ //创建连接 try { myIP = IPAddress.Parse("192.168.17.128"); } catch { MessageBox.Show("您输入的IP格式不正确,请重新输入!"); } }private void button1_Click(object sender, EventArgs e){ try { Myserver = new IPEndPoint(myIP, Int32.Parse("55555")); connectSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); connectSock.Connect(Myserver); Byte[] sendByte = new Byte[64]; string send = "1" + textBox1.Text+ " "+textBox2.Text; NetworkStream netStream = new NetworkStream(connectSock); sendByte = System.Text.Encoding.Default.GetBytes(send.ToCharArray()); netStream.Write(sendByte, 0, sendByte.Length); netStream.Flush(); Byte[] Rec = new Byte[64]; netStream.Read(Rec, 0, Rec.Length); string RecMessage = "您好 \n" + " 您还有" + System.Text.Encoding.Default.GetString(Rec); string str = System.Text.Encoding.Default.GetString(Rec); if (!str.Equals("Y")) { Form4 f = new Form4(); f.Show(); this.Hide(); connectSock.Close(); } else{ textBox1.Text = ""; textBox2.Text = ""; connectSock.Close(); textBox1.Focus(); } } catch { MessageBox.Show("连接尚未建立,无法发送!"); } }private void button2_Click(object sender, EventArgs e){ Form3 f = new Form3(); f.Show(); this.Hide(); } }}
- 手机模拟缴费二(c/m/s)
- 模拟手机交费系统 (c/m/s)
- 苹果证书缴费(二)
- 【黑马.Net程序员】模拟手机缴费系统,功能不全面
- java-----C/S编程----模拟手机业务办理
- HDU 5641 King's Phone 手机解锁 (模拟)
- 模拟赛 改造二叉树(时间限制 1s;空间限制 256M)
- 模拟赛 长途旅行(时间限制:1s;空间限制:256M)
- java多线程模拟M/M/C(马科洛夫队列)
- POJ 1591 M*A*S*H 水模拟
- Shuffle'm Up(模拟)
- Shuffle'm Up (模拟)
- 2013杭州站C - Zhuge Liang's Password(模拟)
- pat甲1116. Come on! Let's C(模拟)
- 浅谈 offsetof(s,m)
- oj(二)m
- 深入 WIN2000注册表 (17) M i c r o s o f t事务处理服务器
- 深入 WIN2000注册表 (17) M i c r o s o f t事务处理服务器
- java实现页面访问量统计的实例
- 关于Memcache的连接
- LeetCode 52 Maximum Subarray
- 程序员必须知道的10大基础实用算法及其讲解
- jQuery的ajax的form提交方法应用
- 手机模拟缴费二(c/m/s)
- 谁也拦不住你
- Swift函数
- 求高精度幂数
- 【HDU】1255 覆盖的面积 线段树+扫描线
- 设计模式的分类
- JAVA 代码优化
- 那些rails的第一道坎
- Swift闭包(Closure)