用到的文本编码:
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class VoteMsgTextCoder implements VoteMsgCoder {
/*
* Wire Format "VOTEPROTO" <"v" | "i"> [<RESPFLAG>] <CANDIDATE> [<VOTECNT>]
* Charset is fixed by the wire format.
*/
// Manifest constants for encoding
public static final String MAGIC = "Voting";
public static final String VOTESTR = "v";
public static final String INQSTR = "i";
public static final String RESPONSESTR = "R";
public static final String CHARSETNAME = "US-ASCII";
public static final String DELIMSTR = " ";
public static final int MAX_WIRE_LENGTH = 2000;//指定传输的最大字节长度.如果超过了这个长度会造成消息被截断,接收信息就不全.
public byte[] toWire(VoteMsg msg) throws IOException {
String msgString = MAGIC + DELIMSTR + (msg.isInquiry() ? INQSTR : VOTESTR)
+ DELIMSTR + (msg.isResponse() ? RESPONSESTR + DELIMSTR : "")
+ Integer.toString(msg.getCandidateID()) + DELIMSTR
+ Long.toString(msg.getVoteCount());
byte data[] = msgString.getBytes(CHARSETNAME);
return data;
}
public VoteMsg fromWire(byte[] message) throws IOException {
ByteArrayInputStream msgStream = new ByteArrayInputStream(message);
//Scanner默认是使用空格作为定界符
Scanner s = new Scanner(new InputStreamReader(msgStream, CHARSETNAME));
boolean isInquiry;
boolean isResponse;
int candidateID;
long voteCount;
String token;
try {
token = s.next();
if (!token.equals(MAGIC)) {
throw new IOException("Bad magic string: " + token);
}
token = s.next();
if (token.equals(VOTESTR)) {
isInquiry = false;
} else if (!token.equals(INQSTR)) {
throw new IOException("Bad vote/inq indicator: " + token);
} else {
isInquiry = true;
}
token = s.next();
if (token.equals(RESPONSESTR)) {
isResponse = true;
token = s.next();
} else {
isResponse = false;
}
// Current token is candidateID
// Note: isResponse now valid
candidateID = Integer.parseInt(token);
if (isResponse) {
token = s.next();
voteCount = Long.parseLong(token);
} else {
voteCount = 0;
}
} catch (IOException ioe) {
throw new IOException("Parse error...");
}
return new VoteMsg(isResponse, isInquiry, candidateID, voteCount);
}
}
一.服务端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Arrays;
public class VoteServerUDP {
public static void main(String[] args) throws IOException {
DatagramSocket sock = new DatagramSocket(9000); //服务端当然要指定端口
//接收的缓冲字节码数组
byte[] inBuffer = new byte[VoteMsgTextCoder.MAX_WIRE_LENGTH];
//使用与客户端同样的基于文本的编码器
VoteMsgCoder coder = new VoteMsgTextCoder();
//与前文一样,用于处理投票请求
VoteService service = new VoteService();
while (true) {
//接收端的数据报文包实例指定缓冲字节码数组与长度即可(放在这个位置很重要,需要重置缓冲区)
DatagramPacket packet = new DatagramPacket(inBuffer, inBuffer.length);
//进行接收(此方法是阻塞的,直到一个数据报文包已接收)
sock.receive(packet);
//获取实际有效的字节码
byte[] encodedMsg = Arrays.copyOfRange(packet.getData(), 0, packet.getLength());
System.out.println("Handling request from " + packet.getSocketAddress() + " (" + encodedMsg.length + " bytes)");
try {
//反将字节码转成VoteMsg实例(相当于反序列化)
VoteMsg msg = coder.fromWire(encodedMsg);
//处理投票业务逻辑
msg = service.handleRequest(msg);//返回的是处理后的一个VoteMsg(包含候选人的票数等信息)
//只需要简单重置消息数据
packet.setData(coder.toWire(msg));
System.out.println("Sending response (" + packet.getLength() + " bytes):");
System.out.println(msg);
//发送时,会将这个数据报文包原来的源主机和源端口作为目标主机和目标端口
sock.send(packet);
} catch (IOException ioe) {
System.err.println("Parse error in message: " + ioe.getMessage());
}
}
}
}
还有服务端处理投票请求的服务类与前文一样
二.客户端
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 {
Socket sock = new Socket("127.0.0.1", 9000);
OutputStream out = sock.getOutputStream();
//创建一个二进制编码实例
VoteMsgCoder coder = new VoteMsgBinCoder();
//创建一个基于长度的成帧方法实例
Framer framer = new LengthFramer(sock.getInputStream());
//创建一个查询请求消息
VoteMsg msg = new VoteMsg(false, true, CANDIDATEID, 0);
//将消息转成字节码(相当于序列化))
byte[] encodedMsg = coder.toWire(msg);
System.out.println("Sending Inquiry (" + encodedMsg.length + " bytes): ");
System.out.println(msg);
//发送查询请求
framer.frameMsg(encodedMsg, out);
//改为投票请求
msg.setInquiry(false);
//将消息转成字节码(相当于序列化)
encodedMsg = coder.toWire(msg);
System.out.println("Sending Vote (" + encodedMsg.length + " bytes): ");
//发送投票请求
framer.frameMsg(encodedMsg, out);
//从响应取出查询消息
encodedMsg = framer.nextMsg();
//转为VoteMsg实例(相当于反序列化)
msg = coder.fromWire(encodedMsg);
System.out.println("Received Response (" + encodedMsg.length + " bytes): ");
System.out.println(msg);
//从响应取出投票消息
encodedMsg = framer.nextMsg();
msg = coder.fromWire(encodedMsg);
System.out.println("Received Response (" + encodedMsg.length + " bytes): ");
System.out.println(msg);
//关闭socket
sock.close();
}
}