CSFramework之会话层,服务器与客户端(源码)

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) {
				// 此时的IO异常可能是因为对端异常掉线,没有正常的使用close方法,所以
				// goon并没有被赋值为false
				
				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;	//相当于将我们的server中需要告诉的APP的信息通过这个接口传递给APP至于APP怎么实现我们不用关心
	private ClientPool clientPool;			//IListener中有一个未实现的方法 public abstract void dealMessage(String message);
	
	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) {  // -> if (this.goon)
			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) { // 服务器告诉每一个listener
		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() {
		// 服务器异常掉线,这个我们框架管不了,应该交给客户端的APP层,至于具体的实现形式我们不关心
		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;
	}
}

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值