说实话,通过这个案例我喜欢上了《Java TCP/IP Socket编程》(原书第2版)这本书。要是让我自己写这个程序的话也可能很快写出来,但是健壮性,安全性,可复用性和面向对象的编程思想不可能用的这么全面。而且作者考虑的思路更是值得借鉴,这不仅仅是一本将Socket编程的书了!
import java.io.IOException;
public interface VoteMsgCoder {
byte[] toWire(VoteMsg msg) throws IOException;//负责对VoteMsg编码
VoteMsg fromWire(byte[] input) throws IOException;//负责将输入解码成VoteMsg
}
public interface VoteMsgCoder {
}
-
基于文本的表示方法,很简单,就是把VoteMsg中携带的信息按照文本的方式进行编码,也就是将如下格式作为发送的信息。
"VOTEPROTO" <"v" | "i"> [<RESPFLAG>] <CANDIDATE> [<VOTECNT>]其中"VOTEPROTO"为头信息。代码VoteMsgTextCoder.java。 -
二进制表示方法,顾名思义,就是把信息编程二进制的消息传递出去。代码VoteMsgBinCoder.java。
-
没有更多信息,阻塞等待,发送者也在等待反馈,造成死锁 -
读到了其他发送者的信息,造成错误。
-
基于定界符:返回一个特殊字节序列,但是不能包含定界符,使用填充技术,但是发送者和接受者都得扫描信息。代码DelimFramer.java。 -
显示长度:要知道消息长度的上限,小于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;//负责从输入中去除帧信息,获得真正消息
}
import java.io.OutputStream;
public interface Framer {
}
- 服务器端建立serverSocket等待用户
- 客户端建立clientSocket和服务器链接
- 客户端新建投票信息voteMessage
- 客户端通过VoteMsgCoder.toWire(voteMessage)对该信息进行编码成message,同时添加头信息
- 客户端通过Framer.frameMsg(message, clientSocket.getOutputStream)发送给相应的服务器端
- 服务器端通过Framer.nextMsg()方法取得带解码的byte数组message
- 服务器端通过VoteMsgCoder.fromWire(message),获得相应的投票信息voteMessage。
- 服务器此时应该处理投票信息voteMessage,给客户端一个反馈信息。
了解了过程,那么客户端和服务器端就很好实现啦!
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();
}
}
}
}
import java.net.ServerSocket;
import java.net.Socket;
public class VoteServerTCP {
}
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();
}
}
import java.net.Socket;
public class VoteClientTCP {
}