投票协议:构建和解析协议消息

我们再看一个简单的例子,对在实现别人定义的协议时可能用到的技术进行了介绍。这个例子程序是一个简单的"投票"协议,如图3.2所示。这里,一个客户端向服务器发送了一个请求消息,消息中包含了一个候选人ID,范围是01000

Vote Reques:投票请求, Candidate:候选人,Vote Count:选票总数

 程序支持两种请求。一种是查询(inquiry),即向服务器询问给定候选人当前获得的投票总数。服务器发回一个响应消息,包含了原来的候选人ID和该候选人当前(查询请求收到时)获得的选票总数。另一种是投票(voting)请求,即向指定候选人投一票。服务器对这种请求也发回响应消息,包含了候选人ID和其获得的选票数(包括了刚投的一票)。

 在实现一个协议时,定义一个专门的类来存放消息中所包含的信息是大有裨益的。该类提供了操作消息中的字段的方法--同时用来维护不同字段之间的不变量。在我们的例子中,客户端和服务器端发送的消息都非常简单,它们唯一的区别是服务器端发送的消息包含了选票总数和一个表示响应消息(不是请求消息)的标志。因此,我们可以用一个类来表示客户端和服务器端的两种消息。VoteMsg.java类展示了每条消息中的基本信息:

布尔值isInquiry,其值为true时表示该消息是查询请求(为false时表示该消息是投票信息);

 布尔值isResponse,指示该消息是响应(由服务器发送)还是请求;

 整型变量candidateID指示了候选人的ID

 长整型变量voteCount指示出所查询的候选人获得的总选票数。

 这个类还维护了以下字段间的不变量:

 candidateID的范围是01000

 voteCount在响应消息中只能是一个非零值(isResponsetrue)。

 voteCount不能为负数。

 VoteMsg.java

0 public class VoteMsg {

1 private boolean isInquiry; // true if inquiry; false if

vote

2 private boolean isResponse;// true if response from

server

3 private int candidateID; // in [0,1000]

4 private long voteCount; // nonzero only in response

5

6 public static final int MAX_CANDIDATE_ID = 1000;

7

8 public VoteMsg(boolean isResponse, boolean isInquiry,

int candidateID, long voteCount)

9 throws IllegalArgumentException {

10 // check invariants

11 if (voteCount != 0 && !isResponse) {

12 throw new IllegalArgumentException("Request vote count

must be zero");

13 }

14 if (candidateID < 0 || candidateID > MAX_CANDIDATE_ID)

{

15 throw new IllegalArgumentException("Bad Candidate ID:

" + candidateID);

16 }

17 if (voteCount < 0) {

18 throw new IllegalArgumentException("Total must be >=

zero");

19 }

20 this.candidateID = candidateID;

21 this.isResponse = isResponse;

22 this.isInquiry = isInquiry;

23 this.voteCount = voteCount;

24 }

25

26 public void setInquiry(boolean isInquiry) {

27 this.isInquiry = isInquiry;

28 }

29

30 public void setResponse(boolean isResponse) {

31 this.isResponse = isResponse;

32 }

33

34 public boolean isInquiry() {

35 return isInquiry;

36 }

37

38 public boolean isResponse() {

39 return isResponse;

40 }

41

42 public void setCandidateID(int candidateID) throws 

IllegalArgumentException {

43 if (candidateID < 0 || candidateID > MAX_CANDIDATE_ID)

{

44 throw new IllegalArgumentException("Bad Candidate ID:

" + candidateID);

45 }

46 this.candidateID = candidateID;

47 }

48

49 public int getCandidateID() {

50 return candidateID;

51 }

52

53 public void setVoteCount(long count) {

54 if ((count != 0 && !isResponse) || count < 0) {

55 throw new IllegalArgumentException("Bad vote count");

56 }

57 voteCount = count;

58 }

59

60 public long getVoteCount() {

61 return voteCount;

62 }

63

64 public String toString() {

65 String res = (isInquiry ? "inquiry" : "vote") + " 

for candidate " + candidateID;

66 if (isResponse) {

67 res = "response to " + res + " who now has " + voteCount

+ " vote(s)";

68 }

69 return res;

70 }

71 } 

VoteMsg.java 

现在我们有了一个用Java表示的投票消息,还需要根据一定的协议来对其进行编码和解码。VoteMsgCoder接口提供了对投票消息进行序列化和反序列化的方法。

 VoteMsgCoder.java

0 import java.io.IOException;

1

2 public interface VoteMsgCoder {

3 byte[] toWire(VoteMsg msg) throws IOException;

4 VoteMsg fromWire(byte[] input) throws IOException;

5 }

VoteMsgCoder.java

 toWire()方法用于根据一个特定的协议,将投票消息转换成一个字节序列,fromWire()方法则根据相同的协议,对给定的字节序列进行解析,并根据信息的内容构造出消息类的一个实例。

 为了介绍不同的信息编码方法,我们展示了两个实现VoteMsgCoder接口的类。一个使用的是基于文本的编码方式,另一个使用的是二进制的编码方式。如果你能确定一直不变地使用一种编码方式,那么toWire()方法和fromWire()方法就可以定义为VoteMsg类的一部分。这里我们这样做是为了强调抽象表示与编码的细节是相互独立的。

 

相关下载:

Java_TCPIP_Socket编程(doc)

http://download.csdn.net/detail/undoner/4940239

 

文献来源:

UNDONER(小杰博客) :http://blog.csdn.net/undoner

LSOFT.CN(琅软中国) :http://www.lsoft.cn

 

原文地址:https://www.cnblogs.com/wuyida/p/6301077.html