Java网络游戏中的服务端与对手通信的操作,本类中的构造函数利用一个网络站点名,打开一个套接字连接到对应主机上的端口如果成功,用InputStreamReader和BufferedReader包装输入,用PrintWriter包装输出。如果失败,向调用者引发一个异常。
view sourceprint?001import java.io.*;
002import java.net.*;
003import java.util.*;
004/**
005 * 该类封装了与服务器和对手之间的通讯
006 **/
007class ServerConnection implements Runnable {
008 private static final int port = 6564; // 端口号
009 private static final String CRLF = "\r\n";
010 private BufferedReader in; // 与服务器间的I/O流
011 private PrintWriter out;
012 private String id, toid = null; // 本地ID和对手ID
013 private Scrabblet scrabblet;
014 /** 构造函数利用一个网络站点名,打开一个套接字连接到对应主机上的端口
015 * 如果成功,用InputStreamReader和BufferedReader包装输入,用PrintWriter
016 * 包装输出。如果失败,向调用者引发一个异常
017 **/
018 public ServerConnection(Scrabblet sc, String site) throws IOException {
019 scrabblet = sc;
020 Socket server = new Socket(site, port);
021 in = new BufferedReader(new InputStreamReader(server.getInputStream()));
022 out = new PrintWriter(server.getOutputStream(), true);
023 }
024 private String readline() {
025 try {
026 return in.readLine();
027 } catch (IOException e) {
028 return null;
029 }
030 }
031 /** 该方法通知服务器本地游戏者的名字 */
032 void setName(String s) {
033 out.println("name " + s);
034 }
035 /** 该方法将自己从服务器的列表上删除 */
036 void delete() {
037 out.println("delete " + id);
038 }
039 /** 绑定对手的id */
040 void setTo(String to) {
041 toid = to;
042 }
043 void send(String s) {
044 if (toid != null)
045 out.println("to " + toid + " " + s);
046 }
047 // 下面的方法都是从客户端向服务器发送一行消息,然后服务器将这些消息
048 // 发送给对手。
049 /** challenge消息初始启动游戏 */
050 void challenge(String destid) {
051 setTo(destid);
052 send("challenge " + id);
053 }
054 /** accept消息用来响应挑战 */
055 void accept(String destid, int seed) {
056 setTo(destid);
057 send("accept " + id + " " + seed);
058 }
059 void chat(String s) {
060 send("chat " + id + " " + s);
061 }
062 /** 每次移动一个字母,发送一个move消息 */
063 void move(String letter, int x, int y) {
064 send("move " + letter + " " + x + " " + y);
065 }
066 /** 每次回合结束时发送turn消息 */
067 void turn(String words, int score) {
068 send("turn " + score + " " + words);
069 }
070 /** 客户退出或离开程序时发送quit消息 */
071 void quit() {
072 send("quit " + id); // tell other player
073 out.println("quit"); // unhook
074 }
075 // 启动线程管理客户方面的网络
076 private Thread t;
077 void start() {
078 t = new Thread(this);
079 t.start();
080 }
081 // 这里显示的静态变量和静态块被用来初始化keys Hashtable, 这里使用这个
082 // 散列表在keystrings中的字符串和数组位置之间映射
083 private static final int ID = 1;
084 private static final int ADD = 2;
085 private static final int DELETE = 3;
086 private static final int MOVE = 4;
087 private static final int CHAT = 5;
088 private static final int QUIT = 6;
089 private static final int TURN = 7;
090 private static final int ACCEPT = 8;
091 private static final int CHALLENGE = 9;
092 private static Hashtable keys = new Hashtable();
093 private static String keystrings[] = {
094 "", "id", "add", "delete", "move", "chat",
095 "quit", "turn", "accept", "challenge"
096 };
097 static {
098 for (int i = 0; i < keystrings.length; i++)
099 keys.put(keystrings[i], new Integer(i));
100 }
101 private int lookup(String s) {
102 Integer i = (Integer) keys.get(s);
103 return i == null ? -1 : i.intValue();
104 }
105 /** 该函数是游戏连接服务器的主循环。它进入一个阻塞调用的readline(),
106 * 这个调用在服务器返回一行文字时返回一个字符串。它使用StringTokenizer
107 * 将一行文字拆成单词。switch语句基于输入行的第一个单词分配合适的代码。
108 **/
109 public void run() {
110 String s;
111 StringTokenizer st;
112 while ((s = readline()) != null) {
113 st = new StringTokenizer(s);
114 String keyword = st.nextToken();
115 switch (lookup(keyword)) {
116 default:
117 System.out.println("bogus keyword: " + keyword + "\r");
118 break;
119 case ID:
120 id = st.nextToken();
121 break;
122 case ADD: {
123 String id = st.nextToken();
124 String hostname = st.nextToken();
125 String name = st.nextToken(CRLF);
126 scrabblet.add(id, hostname, name);
127 }
128 break;
129 case DELETE:
130 scrabblet.delete(st.nextToken());
131 break;
132 case MOVE: {
133 String ch = st.nextToken();
134 int x = Integer.parseInt(st.nextToken());
135 int y = Integer.parseInt(st.nextToken());
136 scrabblet.move(ch, x, y);
137 }
138 break;
139 case CHAT: {
140 String from = st.nextToken();
141 scrabblet.chat(from, st.nextToken(CRLF));
142 }
143 break;
144 case QUIT: {
145 String from = st.nextToken();
146 scrabblet.quit(from);
147 }
148 break;
149 case TURN: {
150 int score = Integer.parseInt(st.nextToken());
151 scrabblet.turn(score, st.nextToken(CRLF));
152 }
153 break;
154 case ACCEPT: {
155 String from = st.nextToken();
156 int seed = Integer.parseInt(st.nextToken());
157 scrabblet.accept(from, seed);
158 }
159 break;
160 case CHALLENGE: {
161 String from = st.nextToken();
162 scrabblet.challenge(from);
163 }
164 break;
165 }
166 }
167 }
168}