手机模拟缴费二(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();        }          }}



0 0
原创粉丝点击