投票系统的设计与实现

       说实话,通过这个案例我喜欢上了《Java TCP/IP Socket编程》(原书第2版)这本书。要是让我自己写这个程序的话也可能很快写出来,但是健壮性,安全性,可复用性和面向对象的编程思想不可能用的这么全面。而且作者考虑的思路更是值得借鉴,这不仅仅是一本将Socket编程的书了!
       既然是投票,那么首先要有投票的信息啊!定义VoteMsg.java类,负责记录这条信息是否是服务器发给客户端的结果信息,如果是客户端发送给服务器,是进行查询还是进行投票,当然还有候选人的ID,如果返回结果的话则需要当前得票数。
       有了投票的信息类,那么就是编码问题了,在网络之间传输肯定无法通过VoteMsg类本身进行传输,这就要对信息进行编码,就是使通信的时候可以理解,为了使该信息具有特殊性(否则双发不知道接收到的信息是否是和投票有关的信息),在信息前面需要添加头信息。那么就需要对消息进行编码和解码,定义接口VoteMsgCoder.java完成功能。
 
import java.io.IOException;

public interface VoteMsgCoder {
  byte[] toWire(VoteMsg msg) throws IOException;//负责对VoteMsg编码
  VoteMsg fromWire(byte[] input) throws IOException;//负责将输入解码成VoteMsg
}
     这里介绍两种方式:
  1.  基于文本的表示方法,很简单,就是把VoteMsg中携带的信息按照文本的方式进行编码,也就是将如下格式作为发送的信息。
    "VOTEPROTO" <"v" | "i"> [<RESPFLAG>] <CANDIDATE> [<VOTECNT>]  其中"VOTEPROTO"为头信息。代码VoteMsgTextCoder.java
  2.  二进制表示方法,顾名思义,就是把信息编程二进制的消息传递出去。代码VoteMsgBinCoder.java

       既然现在已经有了消息和编码能转化为一种双方都能接受的一种格式,下面要做的就是在网络中真正的传输,同时要使接收方知道什么时候才算接受结束,知道什么时候算完成了一条消息的接受工作。

       成帧技术解决了接收端如何定位信息的首尾位置的问题。如果接受者试图从套接字中读取比消息本身更多的字节,将发生两种情况: 
  1.  没有更多信息,阻塞等待,发送者也在等待反馈,造成死锁
  2.  读到了其他发送者的信息,造成错误。

 对于如何确定消息的结束位置,有两种办法:

  1.  基于定界符:返回一个特殊字节序列,但是不能包含定界符,使用填充技术,但是发送者和接受者都得扫描信息。代码DelimFramer.java
  2.  显示长度:要知道消息长度的上限,小于256用1个字节,小于65536需要2个字节。代码LengthFramer.java

 

定义一个接口Framer来完成相应消息提取信息和添加帧信息的功能:
import java.io.IOException;
import java.io.OutputStream;

public interface Framer {
     void frameMsg(byte[] message, OutputStream out) throws IOException;//负责添加帧信息
     byte[] nextMsg() throws IOException;//负责从输入中去除帧信息,获得真正消息
}
     万事俱备,只欠东风,既然已经有了这么多的工具,我们很快就能完成相应的具体功能了。整理一下思路:
  1. 服务器端建立serverSocket等待用户
  2. 客户端建立clientSocket和服务器链接
  3. 客户端新建投票信息voteMessage
  4. 客户端通过VoteMsgCoder.toWire(voteMessage)对该信息进行编码成message,同时添加头信息
  5. 客户端通过Framer.frameMsg(message, clientSocket.getOutputStream)发送给相应的服务器端
  6. 服务器端通过Framer.nextMsg()方法取得带解码的byte数组message
  7. 服务器端通过VoteMsgCoder.fromWire(message),获得相应的投票信息voteMessage。
  8. 服务器此时应该处理投票信息voteMessage,给客户端一个反馈信息。

    此时应该添加一个处理投票的类。明显应该有一个Map<Integer, Long>来存储候选人的得票数。这个类所要处理的很简单,如果本身传过来的就是一个反馈信息,那么直接返回;如果是查询信息,则查找相应Integer对应的Long值,如果没人为他投过票,相应的值为空,那么为它初始化;如果是投票信息,则将相应的值加1后返回。具体代码见VoteService.java

    那么基本流程如下图所示。 第3篇:投票系统的设计与实现

 

了解了过程,那么客户端和服务器端就很好实现啦!
     服务器端:VoteServerTCP.java
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class VoteServerTCP {

  public static void main(String args[]) throws Exception {

    if (args.length != 1) { // Test for correct # of args
      throw new IllegalArgumentException("Parameter(s): <Port>");
    }

    int port = Integer.parseInt(args[0]); // Receiving Port

    ServerSocket servSock = new ServerSocket(port);
    // Change Bin to Text on both client and server for different encoding
    VoteMsgCoder coder = new VoteMsgBinCoder();
    VoteService service = new VoteService();

    while (true) {
      Socket clntSock = servSock.accept();
      System.out.println("Handling client at " + clntSock.getRemoteSocketAddress());
      // Change Length to Delim for a different framing strategy
      Framer framer = new LengthFramer(clntSock.getInputStream());
      try {
        byte[] req;
        while ((req = framer.nextMsg()) != null) {
          System.out.println("Received message (" + req.length + " bytes)");
          VoteMsg responseMsg = service.handleRequest(coder.fromWire(req));
          framer.frameMsg(coder.toWire(responseMsg), clntSock.getOutputStream());
        }
      } catch (IOException ioe) {
        System.err.println("Error handling client: " + ioe.getMessage());
      } finally {
        System.out.println("Closing connection");
        clntSock.close();
      }
    }
  }
}
     客户端:VoteClientTCP.java
import java.io.OutputStream;
import java.net.Socket;

public class VoteClientTCP {

  public static final int CANDIDATEID = 888;

  public static void main(String args[]) throws Exception {

    if (args.length != 2) { // Test for correct # of args
      throw new IllegalArgumentException("Parameter(s): <Server> <Port>");
    }

    String destAddr = args[0]; // Destination address
    int destPort = Integer.parseInt(args[1]); // Destination port

    Socket sock = new Socket(destAddr, destPort);
    OutputStream out = sock.getOutputStream();

    // Change Bin to Text for a different framing strategy
    VoteMsgCoder coder = new VoteMsgBinCoder();
    // Change Length to Delim for a different encoding strategy
    Framer framer = new LengthFramer(sock.getInputStream());

    // Create an inquiry request (2nd arg = true)
    VoteMsg msg = new VoteMsg(false, true, CANDIDATEID, 0);
    byte[] encodedMsg = coder.toWire(msg);

    // Send request
    System.out.println("Sending Inquiry (" + encodedMsg.length + " bytes): ");
    System.out.println(msg);
    framer.frameMsg(encodedMsg, out);

    // Now send a vote
    msg.setInquiry(false);
    encodedMsg = coder.toWire(msg);
    System.out.println("Sending Vote (" + encodedMsg.length + " bytes): ");
    framer.frameMsg(encodedMsg, out);
   
    // Receive inquiry response
    encodedMsg = framer.nextMsg();
    msg = coder.fromWire(encodedMsg);
    System.out.println("Received Response (" + encodedMsg.length
               + " bytes): ");
    System.out.println(msg);

    // Receive vote response
    msg = coder.fromWire(framer.nextMsg());
    System.out.println("Received Response (" + encodedMsg.length
           + " bytes): ");
    System.out.println(msg);
   
    sock.close();
  }
}

 

    运行截图如下:
第3篇:投票系统的设计与实现

第3篇:投票系统的设计与实现

1、引言 1.1编写目的 在完成了针对《学生信息系统》软件市场的前期调查,同时与多位同学进行了全面深入地探讨和分析的基础上,提出了这份软件需求规格说明书。 此需求规格说明书对《学生信息系统》软件做了全面细致的用户需求分析,明确所要开发的软件应具有的功能、性能与界面,使系统分析人员及软件开发人员能清楚地了解用户的需求,并在此基础上进一步提出概要设计说明书和完成后续设计与开发工作。 1.2项目背景 由于文件多,种类多,文件创建者多,创建时间为不定期,要保护好一些公司重要的文件极为不便,同时由于人员的流动,对原有的文件的再现,显得力不从心,有时查找与重新整理文件要浪费许多的人力、物力。 为了有效的共享文件资源,保护好文件,及促进学生信息系统管理的信息化、规范化和集成化,本人多方听取意见、追加和完善大量实用功能,进而了解文件管理的流程,同时结合各部门、各专业与学科管理的方法,开发出一套适合于学生信息系统多而复杂的管理系统。 1.3定义、缩写词和符号 需求:用户解决问题或达到目标所需的条件或功能;系统系统部件要满足标准,规范或其它正式规定文档所需具有的条件或权能。 1.4参考资料 张海藩:《软件工程导论》,清华大学出版社,2008年2月版 黄德才: 《数据库原理及其应用教程》,科学出版社,2006年2月版 2.任务概述 2.1目标 2.1.1开发目标 在当今世界电脑普及的时刻,人们已经习惯用电脑办公,结果自然会产生大量的电子文件,这些文件有宝贵的历史价值,但我们如果将更多的时间花费在寻找这些文件上,即费时又费力。本软件根据此需求进行开发的。 2.1.2应用目标 让学校能够有效的掌握,有效的共享文件资源,保护好文件,及促进学生信息系统管理的信息化、规范化和集成化,实现计算机的智能化管理,以提高工作效率和经济效益。 2.2运行环境 2.2.1硬件环境 A. 一台.NET系统的微机 B.内存足够大 2.2.2软件环境 A.windows 98 以上的操作系统 B.Microsoft Visual studio 2007 C.Microsoft SqlServer 2000 2.3条件与限制 此学生信息系统管理软件是应用于各个学校的。在功能上还可进一步实现安全防范、与E-Mail和因特网电话集成起来,成为学生信息系统管理软件。 3. 数据描述 3.1静态数据 1)Students表 2)Reports表 3)Courses表 4)Log on表 3.2动态数据 输入数据:菜单选项,添加项,查询项,修改项,删除项。 输出数据:由添加、查询、修改、删除所确定的数据库记录集合。 内部生成的数据:查询结果。 3.3数据库描述 本软件采用SQL数据库。 3.4数据流程图 《学生信息系统》软件的数据流程图是比较清晰的,对各功能模块来说都比较有规律。但完整的图比较繁琐,各个功能模块的基本流程图如下。 3.5数据字典 这里给出一个数据元素的字典卡片与具体数据卡片的含义: 名称:学生信息系统 描述:产生学生信息文件送交学生信息目录表 定义:学生信息系统=学生信息类型+安全级别 4. 功能要求 4.1功能划分 本系统有以下功能模块: 1)学生信息录入模块 2)学生信息查询模块 3)学生信息修改模块 4)学生信息删除模块  4.2功能描述 下面详细描述一下各个功能模块: 1)学生信息录入 (1) 学生信息目录管理:只限于一般用户和管理员操作。而且不同的用户级别所操作的信息类型是有限制的。用户可以向里面添加、修改和删除档案类型。也可设置信息类型的级别,以加强它们的保密性。 (2) 学生信息仓库:限于全体操作员工。一般浏览者只能查看学生信息,不能对学生信息做任何的修改。而且不同的用户级别所看到的档案是有限制的。一般用户可向里面添加、修改和删除档案。也可设置学生信息级别,以加强它们的保密性。 2)学生信息查询 (1) 查询单条学生信息记录:主要是适合于全体操作人员的。在窗体上,先可以选择查询的条件,再输入关键字名。按查询即可。查到记录后,也可双击记录即可显示详细信息。 (2) 查询全部学生信息:是给管理员用的,是为了方便管理员查找学生信息,也有按班级查询、按姓名查询和按学号查询。查到记录后,也可双击记录即可显示详细信息。 也有多种查询方法。查到记录后,也可双击记录即可显示详细信息。 3)学生信息修改 (1)修改单条学生信息:主要是适合于全体操作人员的。在窗体上,修改学生信息。修改记录后,也可双击记录即可显示详细信息。 (2)修改全部学生信息:是给管理员用的,是为了方便管理员修改学生信息。修改记录后,也可双击记录即可显示详细信息。 4)学生信息删除 (1)删除单条学生信息:主要是适合于全体操作人员的。在窗体上,删除学生信息。删除记录后,也可双击记录即可显示详细信息。 (2)删除全部学生信息:是给管理员用的,是为了方便管理员删除学生信息。删除记录后,也可双击记录即可显示详细信息。 5.性能需求 5.1数据精确度 A.要按照严格的数据格式输入,否则系统不给予响应进行处理。 B.查询时要保证查全率,所有相应域包含查询关键字的记录都应能查到。因为通常有文件的记录会很多,所以本系统采用了两种方法进行查询:按班级查询、按姓名查询和按学号查询。 5.2时间特性 一般操作的响应时间应在1~2秒内,对软磁盘和打印机的操作也应在可接受的时间内完成。 5.3适应性 满足学校使用的需求(记录量控制在1000项内)。 对前面提到的运行环境要求不应存在困难。 6. 运行需求 6.1用户界面 超越VB的界面,全新感觉,操作简便,一目了然,视图优美等特点。并且采用菜单界面驱动方式,给操作用户带来了极大的便利,对用户友好。对鼠标和键盘单独支持。 6.2硬件接口 本软件不需要特定的硬件或硬件接口进行支撑。 6.3软件接口 运行于Windows 2000及更高版本具有.net的操作系统之上。 6.4故障处理 正常使用时不应出错,若运行时遇到不可恢复的系统错误,也必须保证数据库完好无损。 调试中遇到的问题及解决的方案: 1)遇到跳出“数据库已经关闭“提示信息阻止程序运行时 可以查看一下进行此项操作时,操作的表是否已经被关闭了或者是在没有关闭此表的情况 下又一次运用打开语句打开此表。 2)关于空记录带来的麻烦 有些空记录往往会使程序无法运行。此时你可用“if not isnull”语句先判断一下是否为 空记录,再操作。 3)有些运行错误也可用如下语句排除 On Error GoTo Erropoint Erropoint : Msgbox Err.Descripton Exit sub 或用On Error resume Next 等语句进行处理。 7.其它要求 1)系统的功能实现情况: 用户可在本系统实现各种用户要求的功能 2)系统的安全性: 对于系统的重要数据都有密码保护,具有一定的安全性 3)系统的容错性: 用户输错数据都有提示信息,具有较好的容错性能。 4)系统的封闭性: 用户的封闭性较好,用户基本上在提示信息下输数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值