📄 chessserver.java
字号:
package server;
import java.io.*;
import java.net.*;
import java.awt.*;
import java.util.*;
import java.awt.event.*;
/**
* 显示服务器及用户信息的Panel类
*/
class MessageServerPanel extends Panel {
// 主消息窗口
TextArea messageBoard = new TextArea("", 22, 50, TextArea.SCROLLBARS_VERTICAL_ONLY);
Label statusLabel = new Label("当前连接数:", Label.LEFT);
Panel boardPanel = new Panel();// 主显示区Panel
Panel statusPanel = new Panel();// 连接状态Panel
MessageServerPanel() {
setSize(350, 300);
setBackground(new Color(204, 204, 204));
setLayout(new BorderLayout());
boardPanel.setLayout(new FlowLayout());
boardPanel.setSize(210, 210);
statusPanel.setLayout(new BorderLayout());
statusPanel.setSize(210, 50);
boardPanel.add(messageBoard);
statusPanel.add(statusLabel, BorderLayout.WEST);
add(boardPanel, BorderLayout.CENTER);
add(statusPanel, BorderLayout.NORTH);
}
}
/**
* 服务器线程,主要用于服务器与客户端的通信
*/
class ServerThread extends Thread {
Socket clientSocket;
Hashtable clientDataHash;// Socket与发送数据的流的映射
Hashtable clientNameHash;// Socket与用户名的映射
Hashtable chessPeerHash;// 对弈的两个客户端用户名的映射
MessageServerPanel server;
boolean isClientClosed = false;
/**
* 服务器端线程的构造函数,用于初始化一些对象。
*/
ServerThread(Socket clientSocket, Hashtable clientDataHash, Hashtable clientNameHash, Hashtable chessPeerHash,
MessageServerPanel server) {
this.clientSocket = clientSocket;
this.clientDataHash = clientDataHash;
this.clientNameHash = clientNameHash;
this.chessPeerHash = chessPeerHash;
this.server = server;
}
/**
* 对客户端发来的消息处理的函数,处理后转发回客户端。处理消息的过程比较复杂, 要针对很多种情况分别处理。
*/
public void messageTransfer(String message) {
String clientName, peerName;
/////////////命令处理///////////////////////////////
// 如果消息以“/”开头,表明是命令消息。
if (message.startsWith("/")) {
// 如果消息以“/list”开头,则将其回馈到客户端以更新用户列表
if (message.equals("/list")) {
Feedback(getUserList());
}
// 如果消息以"/creatgame [inchess]"开头,则修改clientNameHash映射
// 和chessPeerHash映射。
else if (message.startsWith("/creatgame [inchess]")) {
//
String chessServerName = message.substring(20);
synchronized (clientNameHash) {
clientNameHash.put(clientSocket, message.substring(11));
}
synchronized (chessPeerHash) {//刚创建,等待其他人加入
chessPeerHash.put(chessServerName, "wait");
}
Feedback("/yourname " + clientNameHash.get(clientSocket));
chessPeerTalk(chessServerName, "/OK");
publicTalk(getUserList());
}
// 如果消息以“/joingame”开头,则将消息的服务端名字和本地用户名提取出来,
// 然后修改clientNameHash表和chessPeerHash表。
if (message.startsWith("/joingame ")) {
StringTokenizer userToken = new StringTokenizer(message, " ");
String getUserToken, serverName, selfName;
String[] chessNameOpt = {"0", "0"};
int getOptNum = 0;
// 提取服务端用户名和本地用户名
while (userToken.hasMoreTokens()) {
getUserToken = (String) userToken.nextToken(" ");
if (getOptNum >= 1 && getOptNum <= 2) {
chessNameOpt[getOptNum - 1] = getUserToken;
}
getOptNum++;
}
serverName = chessNameOpt[0];
selfName = chessNameOpt[1];
// 如果有服务端在等待开始棋局
if (chessPeerHash.containsKey(serverName) && chessPeerHash.get(serverName).equals("wait")) {
// 修改Socket和名字映射
synchronized (clientNameHash) {
clientNameHash.put(clientSocket, ("[inchess]" + selfName));
}
// 修改chessPeerHash映射
synchronized (chessPeerHash) {
chessPeerHash.put(serverName, selfName);
}
publicTalk(getUserList());
chessPeerTalk(selfName, ("/peer " + "[inchess]" + serverName));
chessPeerTalk(serverName, ("/peer " + "[inchess]" + selfName));
} else {
chessPeerTalk(selfName, "/reject");
try {
clientClose();
} catch (Exception ez) {
}
}
}
// 如果消息以“/[inchess]”开头,则获取要发送消息的用户名和发送的消息
// 然后发送出去。
else if (message.startsWith("/[inchess]")) {
int firstLocation = 0, lastLocation;
lastLocation = message.indexOf(" ", 0);
peerName = message.substring((firstLocation + 1), lastLocation);
message = message.substring((lastLocation + 1));
if (chessPeerTalk(peerName, message)) {
Feedback("/error");
}
}
// 如果消息以“/giveup”开头,则判断是对弈双方哪方放弃了。
else if (message.startsWith("/giveup ")) {
String chessClientName = message.substring(8);
if (chessPeerHash.containsKey(chessClientName)
&& !((String) chessPeerHash.get(chessClientName)).equals("wait")) {
// 如果服务方放弃,则发送消息“/youwin”表明对方获胜
chessPeerTalk((String) chessPeerHash.get(chessClientName), "/youwin");
//剔除这对对弈的人。。
synchronized (chessPeerHash) {
chessPeerHash.remove(chessClientName);
}
}
if (chessPeerHash.containsValue(chessClientName)) {
// 如果客户方放弃,也发送消息“/youwin”表明对方获胜
chessPeerTalk((String) getHashKey(chessPeerHash, chessClientName), "/youwin");
synchronized (chessPeerHash) {
chessPeerHash.remove((String) getHashKey(chessPeerHash, chessClientName));
}
}
}
// 如果找不到发送消息的用户,则输出消息说“没有这个用户”
else {
int firstLocation = 0, lastLocation;
lastLocation = message.indexOf(" ", 0);
if (lastLocation == -1) {
Feedback("无效命令");
return;
} else {
peerName = message.substring((firstLocation + 1), lastLocation);
message = message.substring((lastLocation + 1));
message = (String) clientNameHash.get(clientSocket) + ">" + message;
if (peerTalk(peerName, message)) {
Feedback("没有这个用户:" + peerName + "\n");
}
}
}
}
// //////////////////////////////////////////////
// 如果不以“/”开头,表明是普通消息,直接发送
else {
message = clientNameHash.get(clientSocket) + ">" + message;
server.messageBoard.append(message + "\n");
publicTalk(message);
server.messageBoard.setCaretPosition(server.messageBoard.getText().length());
}
}
/**
* 发送公共消息的函数,将消息向每个客户端都发送一份
*/
public void publicTalk(String publicTalkMessage) {
synchronized (clientDataHash) {
//枚举遍历所有客户端输出流。。
for (Enumeration enu = clientDataHash.elements(); enu.hasMoreElements();) {
DataOutputStream outData = (DataOutputStream) enu.nextElement();
try {
//输出信息。。这里会阻塞
outData.writeUTF(publicTalkMessage);
} catch (IOException es) {
//打印异常堆栈。。。终止程序。。
es.printStackTrace();
}
}
}
}
/**
* 选择对象发送消息,参数peerTalk为发送的用户名,后面的参数为发送的消息
*/
public boolean peerTalk(String peerTalk, String talkMessage) {
//
for (Enumeration enu = clientDataHash.keys(); enu.hasMoreElements();) {
Socket userClient = (Socket) enu.nextElement();
// 找到发送消息的对象,获取它的输出流以发送消息
if (peerTalk.equals((String) clientNameHash.get(userClient))
&& !peerTalk.equals((String) clientNameHash.get(clientSocket))) {
synchronized (clientDataHash) {
DataOutputStream peerOutData = (DataOutputStream) clientDataHash.get(userClient);
try {
peerOutData.writeUTF(talkMessage);
} catch (IOException es) {
es.printStackTrace();
}
}
Feedback(talkMessage);
return (false);
}
// 如果是发给自己的,直接回馈
else if (peerTalk.equals((String) clientNameHash.get(clientSocket))) {
Feedback(talkMessage);
return (false);
}
}
return (true);
}
/**
* 此函数也用于选择发送消息,但不能发送给自己。
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -