库模块LogoutActivity对数据库库进行操作,同时和服务端建立TCP连接把用户信息发送到服务端。
客户端程序清单:
GoogleCardHomeActivity.java:客户端主界面。 LoginActivity.java:用户进库主界面。 LogoutActivity.java:用户出库主界面。
SocketServer.java:Serivce服务,负责监听服务端发送的出库信息。 AppUtil.java:工具集程序。
SendSMSTask.java:发送短信提醒的定时器。 SqlHelper.java:数据库操作类。
ApplicationContainer.java:用于记录所有Activity对象,以便退出时销毁。 NavDrawerItem.java:侧边导航栏中的项目。
NavDrawerListAdapter.java:侧边导航栏listview的adapter。
4.4 主要模块分析
4.4.1 服务端数据保存模块
经分析发现每个用户的进库信息只有姓名,车牌号码,手机号,和进库时间这四个项目,数据量并不大,所以服务端用户采用轻量级的XML文件存储用户数据,这样做的好处是服务端不需要部署数据库,降低了使用成本。
C#使用XmlDocument类对XML文件进行解析。XmlDocument将XML视为树状结构,它装载XML文档,并在内存中构建该文档的树状结构。
在程序中,首先检测程序路径下是否存在data.xml文件,该文件用来存储用户信息,如车主姓名,入库时间等。如果不存在则先在xml容器中创建XmlDeclaration并且调用CreateElement(\创建名为GarageInfo的根节点,之后存入data.xml中。一个新创建的data.xml如下:
每次启动程序时,需要对data.xml文件进行解析,本系统使用了自己编写的方法parse_xml(),该方法首先查找到data.xml文件中根节点的GrageInfo,随后通过for循环遍历根节点下的孩子节点获得所有用户信息,然后该方法返回一个用户数据结构数组。通过该数组能够获得xml文件中所有用户信息。parse_xml()方法的代码如下:
15
private User[] parse_xml(String filename) { XmlDocument doc = new XmlDocument(); doc.Load(filename);
XmlNode node = doc.SelectSingleNode(\ XmlNodeList nodeList = node.ChildNodes; int i = nodeList.Count;
User[] all_usr = new User[i]; //read all data into User[] array for(int j=0;j
XmlNode internal_node = nodeList.Item(j); if (internal_node != null){ User user = new User();
user.NAME = internal_node.Attributes[\
user.CAR_NUMBER = internal_node.Attributes[\ user.PHONE_NUMBER = internal_node.Attributes[\
user.TIME = internal_node.Attributes[\ all_usr[j] = user; } }
return all_usr; }
当客户端发送用户进库信息时,需要要把用户进库信息写入xml文件,本系统使用自定义的write_xml()方法。调用该方法时需要提供的参数为用户名,车牌号,电话号码,以及入库时间。该方法首先选择XML文件中的根节点GarageInfo,然后将所需保存用户信息作为一个孩子节点插入根节点中,关键代码如下:
private void write_xml(String NAME, String CAR_NUMBER, String PHONE_NUMBER, String TIME){ //加入另外一个元素
XmlDocument doc = new XmlDocument(); doc.Load(\
XmlNode root = doc.SelectSingleNode(\
XmlElement xe1 = doc.CreateElement(\创建一个
xe1.SetAttribute(\
xe1.SetAttribute(\
xe1.SetAttribute(\ root.AppendChild(xe1); doc.Save(\ }
4.4.2 服务端监听模块
在用户点击服务端上的侦听按钮之后,服务端会初始化一个ServerSocket,并开始对
16
端口7631进行监听,为了使监听程序不至于阻塞主线程,需要新开一个线程,在此线程中将监听程序放入一个while(true)循环中。一旦客户端与服务端完成TCP三次握手连接后,serverSocket.Accept()便会返回一个客户端套接字clientSocket。每当一个客户端与服务端建立一个TCP连接时,都会新开一个线程ReceiveData用来接收数据。这样做可以提升服务器的并发访问性能。关键代码如下:
//set connection
ipep = new IPEndPoint(IPAddress.Any, 7631);
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(ipep); serverSocket.Listen(10);
//start a listener thread in order to avoid jamming the main thread listenerThread.Start();
侦听线程代码:
private void listener(){ while (true){ try{
//create a new thread when a tcp connection accepted to recive data clientSocket = serverSocket.Accept();
Thread clientThread = new Thread(new ThreadStart(ReceiveData)); clientThread.IsBackground = true; clientThread.Start(); }
catch (Exception ex){
MessageBox.Show(\ } } }
当程序获取了一个clientSocket之后,系统需要获得其中汽车进库的数据,字符串对象clientcommand 从套接字输入流中提取客户端所发来的信息,然后将其写入用户列表listview和xml文件中,这里程序使用了C#自带的线程同步机制Invoke()来确保多线程的安全写入。在读取数据完成后,程序释放套接字、关闭TCP连接和数据接收线程,以便释放资源。代码如下:
private void ReceiveData(){ bool keepalive = true; Socket s = clientSocket;
Byte[] buffer = new Byte[1024];
clientep = (IPEndPoint)s.RemoteEndPoint; while (keepalive){
17
int bufLen = 0; //client socket recive bufLen = s.Available;
s.Receive(buffer, 0, bufLen, SocketFlags.None); clientep = (IPEndPoint)s.RemoteEndPoint; //get stuff from buffer
string clientcommand = System.Text.Encoding.UTF8.GetString(buffer).Substring(0, bufLen);
string[] stringSeparators = new string[] { \ string[] split = clientcommand.Split(stringSeparators, StringSplitOptions.RemoveEmptyEntries);
Invoke(new MethodInvoker(delegate(){
add_listitem(split[0], split[1], split[2], split[3]);
write_xml(split[0], split[1], split[2], split[3].Trim()); }));
keepalive = false; }
s.Shutdown(SocketShutdown.Receive); s.Close();
Thread.CurrentThread.Abort(); }
4.4.3 客户端汽车进库模块
当用户在智能手机上输入用户信息进行进库操作时,程序首先从用户界面控件中提取文本信息,然后新开一个线程,将用户信息保存到数据库中,并且通过套接字将用户信息发往服务器,这里没有将用户数据结构类序列化,而是将用户信息以字符串的形式发送到服务端,使用EOF分隔符来分割用户数据信息。关键代码如下:
Runnable doBackGroundOperation = new Runnable() { public void run() { if(helper.insert(name, carNumber, phoneNumber, time)){ mHandler.post(new Runnable(){ startActivity(intent); try { // 实例化Socket Socket socket = new Socket(HOST, PORT); PrintWriter out = new PrintWriter(new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())), true); out.println(name+\ out.close(); socket.shutdownOutput(); socket.close(); } catch (IOException e) { e.printStackTrace(); }
18
相关推荐: