首先,我们介绍一个用文本方式对消息进行编码的版本。该协议指定使用US-ASCII字符集对文本进行编码。消息的开头是一个所谓的"魔术字符串",即一个字符序列,用于接收者快速将投票协议的消息和网络中随机到来的垃圾消息区分开。投票/查询布尔值被编码成字符形式,'v'表示投票消息,'i'表示查询消息。消息的状态,即是否为服务器的响应,由字符'R'指示。状态标记后面是候选人ID,其后跟的是选票总数,它们都编码成十进制字符串。
VoteMsgTextCoder类提供了一种基于文本的VoteMsg编码方法。
VoteMsgTextCoder.java
0 import java.io.ByteArrayInputStream;
1 import java.io.IOException;
2 import java.io.InputStreamReader;
3 import java.util.Scanner;
4
5 public class VoteMsgTextCoder implements VoteMsgCoder
{
6 /*
7 * Wire Format "VOTEPROTO" <"v"|"i"> [<RESPFLAG>]
<CANDIDATE> [<VOTECNT>]
8 * Charset is fixed by the wire format.
9 */
10
11 // Manifest constants for encoding
12 public static final String MAGIC = "Voting";
13 public static final String VOTESTR = "v";
14 public static final String INQSTR = "i";
15 public static final String RESPONSESTR = "R";
16
17 public static final String CHARSETNAME = "US-ASCII";
18 public static final String DELIMSTR = " ";
19 public static final int MAX_WIRE_LENGTH = 2000;
20
21 public byte[] toWire(VoteMsg msg) throws IOException
{
22 String msgString = MAGIC + DELIMSTR + (msg.isInquiry() ?
INQSTR : VOTESTR)
23 + DELIMSTR + (msg.isResponse() ? RESPONSESTR +
DELIMSTR : "")
24 + Integer.toString(msg.getCandidateID()) + DELIMSTR
25 + Long.toString(msg.getVoteCount());
26 byte data[] = msgString.getBytes(CHARSETNAME);
27 return data;
28 }
29
30 public VoteMsg fromWire(byte[] message) throws
IOException {
31 ByteArrayInputStream msgStream = new
ByteArrayInputStream(message);
32 Scanner s = new Scanner(new
InputStreamReader(msgStream, CHARSETNAME));
33 boolean isInquiry;
34 boolean isResponse;
35 int candidateID;
36 long voteCount;
37 String token;
38
39 try {
40 token = s.next();
41 if (!token.equals(MAGIC)) {
42 throw new IOException("Bad magic string: " + token);
43 }
44 token = s.next();
45 if (token.equals(VOTESTR)) {
46 isInquiry = false;
47 } else if (!token.equals(INQSTR)) {
48 throw new IOException("Bad vote/inq indicator: " +
token);
49 } else {
50 isInquiry = true;
51 }
52
53 token = s.next();
54 if (token.equals(RESPONSESTR)) {
55 isResponse = true;
56 token = s.next();
57 } else {
58 isResponse = false;
59 }
60 // Current token is candidateID
61 // Note: isResponse now valid
62 candidateID = Integer.parseInt(token);
63 if (isResponse) {
64 token = s.next();
65 voteCount = Long.parseLong(token);
66 } else {
67 voteCount = 0;
68 }
69 } catch (IOException ioe) {
70 throw new IOException("Parse error...");
71 }
72 return new VoteMsg(isResponse, isInquiry, candidateID,
voteCount);
73 }
74 }
VoteMsgTextCoder.java
toWire()方法简单地创建一个字符串,该字符串中包含了消息的所有字段,并由空白符隔开。fromWire()方法首先检查"魔术"字符串,如果在消息最前面没有魔术字符串,则抛出一个异常。这里说明了在实现协议时非常重要的一点:永远不要对从网络来的任何输入进行任何假设。你的程序必须时刻为任何可能的输入做好准备,并能够很好地对其进行处理。在这个例子中,如果接收到的不是期望的消息,fromWire()方法将抛出一个异常,否则,就使用Scanner实例,根据空白符一个一个地获取字段。注意,消息的字段数与其是请求消息(由客户端发送)还是响应消息(由服务器发送)有关。如果输入流提前结束或格式错误,fromWire()方法将抛出一个异常。
相关下载:
Java_TCPIP_Socket编程(doc)
http://download.csdn.net/detail/undoner/4940239
文献来源:
UNDONER(小杰博客) :http://blog.csdn.net/undoner
LSOFT.CN(琅软中国) :http://www.lsoft.cn