Communication
public abstract class Communication implements Runnable{
public static final Gson gson = new GsonBuilder().create();
protected Socket socket;
protected DataInputStream dis;
protected DataOutputStream dos;
protected volatile boolean goon;
protected Communication(Socket socket) throws IOException {
this.socket = socket;
this.dis = new DataInputStream(this.socket.getInputStream());
this.dos = new DataOutputStream(this.socket.getOutputStream());
this.goon = true;
new Thread(this, "LOL只会玩提莫").start();
}
public abstract void dealNetMessage(NetMessage netMessage);
public abstract void peerAbnormalDrop();
protected void send(NetMessage netMessage) {
try {
this.dos.writeUTF(gson.toJson(netMessage));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
String message = "";
while(this.goon) {
try {
message = this.dis.readUTF();
dealNetMessage(gson.fromJson(message, NetMessage.class));
} catch (IOException e) {
if (this.goon == true) {
this.goon = false;
peerAbnormalDrop();
}
}
}
}
public void close() {
this.goon = false;
if (dis != null) {
try {
this.dis.close();
} catch (IOException e) {
} finally {
this.dis = null;
}
}
if (dos != null) {
try {
this.dos.close();
} catch (IOException e) {
} finally {
this.dos = null;
}
}
if (this.socket != null && !this.socket.isClosed()) {
try {
this.socket.close();
} catch (IOException e) {
} finally {
this.socket = null;
}
}
}
}
ENetCommand
public enum ENetCommand {
OUT_OF_ROOM,
ID,
OFFLINE,
FOREC_DOWN,
TO_ONE,
TO_OTHER,
TO_SP_OTHER,
}
NetMessage
public class NetMessage {
private ENetCommand command;
private String message;
private String action;
public NetMessage() {
}
public ENetCommand getCommand() {
return command;
}
public NetMessage setCommand(ENetCommand command) {
this.command = command;
return this;
}
public String getMessage() {
return message;
}
public NetMessage setMessage(String message) {
this.message = message;
return this;
}
String getAction() {
return action;
}
NetMessage setAction(String action) {
this.action = action;
return this;
}
}
IListener,ISpeaker
public interface IListener {
void dealMessage(String message);
}
public interface ISpeaker {
void addListener(IListener listener);
void removeListener(IListener listener);
void speakOut(String message);
}
Server
public class Server implements Runnable, ISpeaker{
public static final int DEFAULT_PORT = 54188;
public static final int DEFAULT_MAX_CLIENT_COUNT = 10;
private int port;
private int maxClientCount;
private ServerSocket serverSocket;
private volatile boolean goon;
private List<IListener> listenerList;
private ClientPool clientPool;
public Server() {
this.goon = false;
this.listenerList = new ArrayList<>();
this.port = DEFAULT_MAX_CLIENT_COUNT;
this.maxClientCount = DEFAULT_MAX_CLIENT_COUNT;
}
ClientPool getClientPool() {
return clientPool;
}
public void startup() {
if (this.goon == true) {
speakOut("服务器已经开启!");
}
try {
speakOut("准备开启服务器... ...");
this.clientPool = new ClientPool();
this.serverSocket = new ServerSocket(this.port);
this.goon = true;
new Thread(this, "SERVER");
speakOut("服务器开启成功!");
} catch (IOException e) {
speakOut("服务器开启出现异常!");
}
}
public void setPort(int port) {
this.port = port;
}
public void setMaxClientCount(int maxClientCount) {
this.maxClientCount = maxClientCount;
}
public void shutdown() {
if (this.goon == false) {
speakOut("服务器已经关闭,请勿重复关闭!");
return;
}
if (this.clientPool.isEmpty()) {
speakOut("即将关闭服务器!");
close();
} else {
speakOut("尚有客户端在线,不能宕机!");
}
}
public void forcedown() {
if (this.goon == false) {
speakOut("服务器已经关闭,请勿重复关闭!");
return;
}
if (this.clientPool.isEmpty()) {
speakOut("即将关闭服务器!");
close();
} else {
List<ServerConversation> clientList = this.clientPool.getClientList();
for (ServerConversation client : clientList) {
client.forcedown();
this.clientPool.removeClient(client);
}
close();
}
}
public Server initServer(String configPath) {
Pro_Parser.load(configPath);
int temp = 0;
try {
temp = Pro_Parser.get("port", int.class);
if (temp != 0) {
this.port = temp;
}
} catch (Exception e) {
}
temp = 0;
try {
temp = Pro_Parser.get("max_client_count", int.class);
if (temp != 0) {
this.maxClientCount = temp;
}
} catch (Exception e) {
}
return this;
}
void toOne(String souceId, String target, String message) {
ServerConversation client = this.clientPool.getClient(target);
client.toOne(souceId, message);
}
void toOther(String souceId, String message) {
List<ServerConversation> clientList = this.clientPool.getClientExcept(souceId);
for (ServerConversation client : clientList) {
client.toOther(souceId, message);
}
}
void toSpOther(String souceId, List<String> targetList, String message) {
List<ServerConversation> clientList = this.clientPool.getSpOther(targetList);
for (ServerConversation client : clientList) {
client.toSpOther(souceId, message);
}
}
@Override
public void addListener(IListener listener) {
if (!listenerList.contains(listener)) {
this.listenerList.add(listener);
}
}
@Override
public void removeListener(IListener listener) {
if (listenerList.contains(listener)) {
this.listenerList.remove(listener);
}
}
@Override
public void run() {
speakOut("开始侦听客户端的连接... ...");
while (this.goon) {
try {
Socket clientSocket = this.serverSocket.accept();
ServerConversation client = new ServerConversation(clientSocket, this);
speakOut("客户端【" + client.getIp() + "】请求连接... ...");
if (this.clientPool.getClientCount() >= this.maxClientCount) {
client.outOfRoom();
} else {
String id = client.getIp() + ":" + client.hashCode();
client.setId(id);
client.sendId(id);
this.clientPool.addClient(client);
speakOut("客户端【" + client.getIp() + "】连接成功!");
}
} catch (IOException e) {
this.goon = false;
}
}
speakOut("终止客户端的连接请求!");
}
@Override
public void speakOut(String message) {
if (listenerList.isEmpty()) {
return;
}
for (IListener listener : this.listenerList) {
listener.dealMessage(message);
}
}
private void close() {
this.goon = false;
if (this.serverSocket != null && !this.serverSocket.isClosed()) {
try {
this.serverSocket.close();
} catch (IOException e) {
} finally {
this.serverSocket = null;
}
}
}
}
ServerConversation
public class ServerConversation extends Communication {
private static final Type type = new TypeToken<List<String>>() {}.getType();
private String id;
private String ip;
private Server server;
protected ServerConversation(Socket socket, Server server) throws IOException {
super(socket);
this.server = server;
this.ip = socket.getInetAddress().getHostAddress();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getIp() {
return ip;
}
@Override
public void dealNetMessage(NetMessage netMessage) {
ENetCommand command = netMessage.getCommand();
String action = netMessage.getAction();
String message = netMessage.getMessage();
switch (command) {
case OFFLINE:
close();
this.server.getClientPool().removeClient(this);
this.server.speakOut("客户端【" + this.id + "】已下线!");
break;
case TO_ONE:
this.server.toOne(this.id, action, message);
break;
case TO_OTHER:
this.server.toOther(this.id,message);
break;
case TO_SP_OTHER:
List<String> targetLsit = Communication.gson.fromJson(action, type);
this.server.toSpOther(this.id, targetLsit, message);
break;
default:
break;
}
}
@Override
public void peerAbnormalDrop() {
this.server.getClientPool().removeClient(this);
this.server.speakOut("客户端【" + this.id + "】异常掉线!");
}
void forcedown() {
send(new NetMessage()
.setCommand(ENetCommand.FOREC_DOWN));
close();
}
void outOfRoom() {
send(new NetMessage()
.setCommand(ENetCommand.OUT_OF_ROOM));
close();
}
void sendId(String id) {
send(new NetMessage()
.setCommand(ENetCommand.ID)
.setMessage(id));
}
void toOne(String souceId, String message) {
send(new NetMessage()
.setAction(souceId)
.setCommand(ENetCommand.TO_ONE)
.setMessage(message));
}
void toOther(String souceId, String message) {
send(new NetMessage()
.setAction(souceId)
.setCommand(ENetCommand.TO_OTHER)
.setMessage(message));
}
void toSpOther(String souceId, String message) {
send(new NetMessage()
.setAction(souceId)
.setCommand(ENetCommand.TO_SP_OTHER)
.setMessage(message));
}
}
IClientAction,ClientActionAdapter
public interface IClientAction {
void serverAbnoramlDrop();
boolean ensureOffline();
void beforeOffline();
void afterOffline();
void serverForcedown();
void outOfRoom();
void afterConnected();
void toOne(String souceId, String message);
void toOther(String souceId, String message);
void toSpOther(String souceId, String message);
}
public class ClientActionAdapter implements IClientAction {
@Override
public void serverAbnoramlDrop() {}
@Override
public boolean ensureOffline() {
return true;
}
@Override
public void beforeOffline() {}
@Override
public void afterOffline() {}
@Override
public void serverForcedown() {}
@Override
public void outOfRoom() {}
@Override
public void afterConnected() {}
@Override
public void toOne(String souceId, String message) {}
@Override
public void toOther(String souceId, String message) {}
@Override
public void toSpOther(String souceId, String message) {}
}
Client
public class Client {
public static final String DEFAULT_IP = "127.0.0.1";
private String ip;
private int port;
private ClientConversation clientConversation;
private IClientAction clientAction;
public Client() {
this.ip = DEFAULT_IP;
this.port = Server.DEFAULT_PORT;
this.clientAction = new ClientActionAdapter();
}
IClientAction getClientAction() {
return clientAction;
}
public void connected() throws IOException {
Socket socket = new Socket(this.ip, this.port);
clientConversation = new ClientConversation(this, socket);
}
public void offline() {
if (this.clientAction.ensureOffline()) {
this.clientAction.beforeOffline();
this.clientConversation.offline();
this.clientAction.afterOffline();
}
}
public String getId() {
String id = null;
while (id == null) {
id = this.clientConversation.getId();
}
return id;
}
public void setIp(String ip) {
this.ip = ip;
}
public void setPort(int port) {
this.port = port;
}
public void setClientConversation(ClientConversation clientConversation) {
this.clientConversation = clientConversation;
}
public void toOne(String target, String message) {
this.clientConversation.toOne(target, message);
}
public void toOther(String message) {
this.clientConversation.toOther(message);
}
public void toSpOther(List<String> targets, String message) {
this.clientConversation.toSpOther(targets, message);
}
public void request(String action, String parameter) {
this.clientConversation.sendRequest(action, parameter);
}
public Client initClient(String configPath) {
Pro_Parser.load(configPath);
int temp = 0;
try {
temp = Pro_Parser.get("port", int.class);
if (temp != 0) {
this.port = temp;
}
} catch (Exception e) {
}
String serverIp = null;
try {
serverIp = Pro_Parser.get("ip", String.class);
if (serverIp != null) {
this.ip = serverIp;
}
} catch (Exception e) {
}
return this;
}
}
ClientConversation
public class ClientConversation extends Communication {
private volatile String id;
private Client client;
protected ClientConversation(Client client, Socket socket) throws IOException {
super(socket);
this.client = client;
}
void toOne(String target, String message) {
send(new NetMessage()
.setCommand(ENetCommand.TO_ONE)
.setAction(target)
.setMessage(message));
}
void toOther(String message) {
send(new NetMessage()
.setCommand(ENetCommand.TO_OTHER)
.setMessage(message));
}
void toSpOther(List<String> targets, String message) {
send(new NetMessage()
.setCommand(ENetCommand.TO_SP_OTHER)
.setAction(Communication.gson.toJson(targets))
.setMessage(message));
}
void sendRequest(String action, String parameter) {
send(new NetMessage()
.setAction(action)
.setCommand(ENetCommand.REQUEST)
.setMessage(parameter));
}
@Override
public void dealNetMessage(NetMessage netMessage) {
ENetCommand command = netMessage.getCommand();
String action = netMessage.getAction();
String message = netMessage.getMessage();
switch (command) {
case FOREC_DOWN:
close();
this.client.getClientAction().serverForcedown();
break;
case OUT_OF_ROOM:
close();
this.client.getClientAction().outOfRoom();
break;
case ID:
while(this.id == null) {
this.id = message;
}
this.client.getClientAction().afterConnected();
break;
case TO_ONE:
this.client.getClientAction().toOne(action, message);
break;
case TO_OTHER:
this.client.getClientAction().toOther(action, message);
break;
case TO_SP_OTHER:
this.client.getClientAction().toSpOther (action, message);
break;
default:
break;
}
}
String getId() {
return id;
}
@Override
public void peerAbnormalDrop() {
this.client.getClientAction().serverAbnoramlDrop();
}
public void offline() {
send(new NetMessage()
.setCommand(ENetCommand.OFFLINE));
close();
}
}
properties文件解析
public class Pro_Parser {
private final static Map<String, String> propertyPool;
static {
propertyPool = new HashMap<String, String>();
}
public static void load(String propertiesPath) {
InputStream is = Pro_Parser.class.getResourceAsStream(propertiesPath);
if (is == null) {
throw new RuntimeException("Properties文件【" + propertiesPath + "】不存在!");
}
try {
Properties properties = new Properties();
properties.load(is);
for (Object objKey : properties.keySet()) {
String key = (String) objKey;
String value = properties.getProperty(key);
propertyPool.put(key, value);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@SuppressWarnings("unchecked")
public static <T> T get(String key, Class<?> klass) throws Exception {
String strValue = Pro_Parser.get(key);
if (strValue == null || strValue.length() <= 0) {
throw new Exception("键[" + key + "]不存在,或未赋值!");
}
return (T) TypeParser.strToValue(klass, strValue);
}
public static String get(String key) {
return propertyPool.get(key);
}
public static List<String> getKeyList() {
if (propertyPool.isEmpty()) {
return null;
}
List<String> keyList = new ArrayList<String>();
for (String key : propertyPool.keySet()) {
keyList.add(key);
}
return keyList;
}
}