package server; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Date; import java.util.Hashtable; import java.util.Iterator; import java.util.Observable; import java.util.Set; import org.apache.log4j.Logger; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.future.IoFuture; import org.apache.mina.core.future.IoFutureListener; import org.apache.mina.core.future.WriteFuture; import org.apache.mina.core.session.IoSession; import exception.NoIpException; import protocol.ProtoHead; import protocol.Msg.KeepAliveMsg; import tools.DataTypeTranslater; import tools.Debug; /** * 网络逻辑层 * * @author Feng * */ public class ServerModel extends Observable { private ServerModel serverModel; private ServerNetwork serverNetwork; Logger logger = Logger.getLogger(this.getClass()); // 心跳包间隔(5秒) public static final int KEEP_ALIVE_PACKET_TIME = 5000; // 轮询"等待client回复"列表(waitClientRepTable)的间隔 public static final int CHECK_WAIT_CLIENT_RESPONSE_DELTA_TIME = 1000; // public static ServerModel instance = new ServerModel(); // Client请求队列 // private LinkedBlockingQueue<NetworkMessage> requestQueue = new // LinkedBlockingQueue<NetworkMessage>(); // 已连接用户信息表(Key 为IoSession.getRemoteAddress().toString) private Hashtable<String, ClientUser> clientUserIpTable = new Hashtable<String, ClientUser>(); private Hashtable<String, ClientUser> clientUserIdTable = new Hashtable<String, ClientUser>(); // 监听客户端回复的表 // private Hashtable<String, WaitClientResponse> waitClientRepTable = new // Hashtable<String, WaitClientResponse>(); public ServerModel() { // init(); } public ServerModel getServerModel() { return serverModel; } public void setServerModel(ServerModel serverModel) { this.serverModel = serverModel; } public ServerNetwork getServerNetwork() { return serverNetwork; } public void setServerNetwork(ServerNetwork serverNetwork) { this.serverNetwork = serverNetwork; } /** * 创建一个随机的MessageId * * @author Feng * @return */ public static byte[] createMessageId() { return DataTypeTranslater.floatToBytes((float) Math.random()); } /** * 初始化 * * @author Feng */ public void init() { // 开始新线程 // new Thread(new DealClientRequest()).start(); new Thread(new KeepAlivePacketSenser()).start(); // new Thread(new CheckWaitClientResponseThread()).start(); } /** * 往客户端请求列表中加入一条请求 * * @param ioSession * @param arrayBytes * @author Feng * @throws InterruptedException */ // public void addClientRequestToQueue(IoSession ioSession, byte[] // byteArray) throws InterruptedException { // requestQueue.put(new NetworkMessage(ioSession, byteArray)); // } /** * 往“已连接用户信息表”中添加一个新用户 * * @param key * @param clientUser * @author Feng * @throws NoIpException */ public void addClientUserToTable(IoSession ioSession, ClientUser clientUser) throws NoIpException { synchronized (clientUserIpTable) { clientUser.onLine = true; clientUserIpTable.put(getIoSessionKey(ioSession), clientUser); } } /** * 设置用户登陆 * * @param clientUser * @param userId * @author Feng */ public void clientUserLogin(ClientUser clientUser, String userId) { clientUser.onLine = true; clientUser.userId = userId; clientUserIdTable.put(userId, clientUser); } /** * 设置用户登陆 * * @param clientUser * @param userId * @author Feng */ public void clientUserLogout(ClientUser clientUser) { try { System.out.println(clientUserIdTable.containsKey(clientUser.userId)); clientUser.onLine = false; clientUserIdTable.remove(clientUser.userId); // clientUser.userId = null; } catch (Exception e) { e.printStackTrace(); logger.error("Logout Error!"); } } /** * 从iosession生成Key * * @param ioSession * @return * @throws NoIpException */ public static String getIoSessionKey(IoSession ioSession) throws NoIpException { // System.err.println("1.2 " + (ioSession.getRemoteAddress() == null)); if (ioSession.getRemoteAddress() == null) throw new NoIpException(); return ((InetSocketAddress) ioSession.getRemoteAddress()).getAddress().toString() + ":" + ((InetSocketAddress) ioSession.getRemoteAddress()).getPort(); } /** * 从“已连接用户信息表”中获取用户 * * @param key * @return ClientUser * @author Feng */ public ClientUser getClientUserFromTable(String key) { synchronized (clientUserIpTable) { return clientUserIpTable.get(key); } } public ClientUser getClientUserFromTable(IoSession ioSession) throws NoIpException { synchronized (clientUserIpTable) { return getClientUserFromTable(getIoSessionKey(ioSession)); } } /** * 根据userId从“已连接用户信息表”中获取用户 * * @param userId * @return */ public ClientUser getClientUserByUserId(String userId) { ClientUser user = clientUserIdTable.get(userId); try { if (user == null || user.userId == null || user.userId.equals("") || user.onLine == false || !user.ioSession.isConnected()) clientUserIdTable.remove(userId); } catch (Exception e) { return null; } return user; // Iterator iterator = clientUserIpTable.keySet().iterator(); // String key; // ClientUser user; // // synchronized (clientUserIpTable) { // while (iterator.hasNext()) { // // key = iterator.next().toString(); // // if (!clientUserIpTable.containsKey(key)) // continue; // // user = clientUserIpTable.get(key); // // if (user.userId == null) // continue; // // if (user.userId.equals(userId)) // return user; // } // } // return null; } /** * 从在线用户信息表删除一个用户 * * @param key */ public void removeClientUserFromTable(String key) { synchronized (clientUserIpTable) { clientUserIpTable.remove(key); } } /** * 添加一个等待客户端回复的监听(服务器向客户端发送消息后,要求客户端回复) * * @param ioSession * @param key * @param messageHasSentww * @author Feng */ // public void addClientResponseListener(IoSession ioSession, byte[] key, // byte[] messageHasSent, // WaitClientResponseCallBack waitClientResponseCallBack) { // WaitClientResponse waitClientResponse = new WaitClientResponse(ioSession, // messageHasSent, waitClientResponseCallBack); // waitClientResponse.time = new Date().getTime(); // // 加入到“等待回复表”中,由CheckWaitClientResponseThread 线程进行轮询 // System.err.println("add Listener, key: " + key.toString()); // waitClientRepTable.put(key.toString(), waitClientResponse); // } /** * 删除一个等待客户端回复的监听(服务器向客户端发送消息后,要求客户端回复) * * @param ioSession * @param key * @param messageHasSent * @author Feng */ // public void removeClientResponseListener(byte[] key) { // synchronized (waitClientRepTable) { // waitClientRepTable.remove(key); // } // } /** * 查找一个等待客户端回复的监听(服务器向客户端发送消息后,要求客户端回复) * * @param ioSession * @param key * @param messageHasSent * @author Feng */ // public WaitClientResponse getClientResponseListener(byte[] key) { // synchronized (waitClientRepTable) { // return waitClientRepTable.get(key); // } // } /** * 广播前的设置变更 */ public void setChange() { super.setChanged(); } public void notify(Object obj) { setChange(); notifyObservers(this); } /** * 用于处理用户请求的线程 * * @author Feng * */ // private class DealClientRequest implements Runnable { // @Override // public void run() { // NetworkMessage networkMessage = null; // // 循环获取新的请求,阻塞式 // while (true) { // try { // networkMessage = requestQueue.take(); // } catch (InterruptedException e) { // e.printStackTrace(); // } // Debug.log("ServerModel", // "'ServerModel' get a request from Client,now transmit to 'ClientRequest_Dispatcher'!"); // if (networkMessage == null) // continue; // ClientRequest_Dispatcher.instance.dispatcher(networkMessage); // // } // } // } /** * 用于定时发送心跳包 * * @author Feng * */ private class KeepAlivePacketSenser implements Runnable, IoFutureListener<IoFuture> { private Iterator iterator; private String key; private Set<String> keySet; @Override public void run() { KeepAliveMsg.KeepAliveSyncPacket.Builder packet = KeepAliveMsg.KeepAliveSyncPacket.newBuilder(); byte[] packetBytes = packet.build().toByteArray(); // 创建心跳包 PacketFromServer packetWillSend; IoBuffer responseIoBuffer; ArrayList<String> keyIterators; while (true) { try { Thread.sleep(KEEP_ALIVE_PACKET_TIME); // 是否开启心跳检验 if (!Server.keepAliveSwitch) continue; ClientUser user; synchronized (clientUserIpTable) { keySet = clientUserIpTable.keySet(); // logger.info("ServerModel Start a new round of sending 'KeepAlivePacket'! " + keySet.size() // + " user exist!"); iterator = keySet.iterator(); while (iterator.hasNext()) { // for (String key : keyIterators) { // Debug.log("ServerModel", "进入发心跳包循环!"); key = iterator.next().toString(); if (!clientUserIpTable.containsKey(key)) continue; user = clientUserIpTable.get(key); // 创建要发送的包 packetWillSend = new PacketFromServer(ProtoHead.ENetworkMessage.KEEP_ALIVE_SYNC.getNumber(), packetBytes); WriteFuture writeFuture = user.ioSession.write(packetWillSend); writeFuture.addListener(this); } } } catch (InterruptedException e) { // Debug.log(Debug.LogType.FAULT, // "'Send KeepAlivePacket Thread' fail at sleep module!\n" + // e.toString()); logger.info("'Send KeepAlivePacket Thread' fail at sleep module!\n" + e.toString()); System.err.println("发行心跳包线程异常! -----睡眠模块"); e.printStackTrace(); } } } @Override public void operationComplete(IoFuture future) { // 掉线处理 if (((WriteFuture) future).isWritten()) { // Debug.log(new String[] { "ServerModel", // "KeepAlivePacketSenser" }, // "User " + ServerModel.getIoSessionKey(user.ioSession) + // " still online!"); } else { // 发送失败,判定掉线 Debug.log("ServerModel", "Client User(" + key + ") was offline,now delete it!"); try { String key = iterator.next().toString(); clientUserIpTable.get(key).ioSession.close(true); } catch (Exception e) { } iterator.remove(); } } } /** * 轮询"等待client回复"列表(waitClientRepTable),检查是否有超时的条目 超时的进行重发 * * @author Feng * */ // private class CheckWaitClientResponseThread implements Runnable { // @Override // public void run() { // long currentTime; // WaitClientResponse waitObj; // String key; // ClientUser clientUser = null; // while (true) { // currentTime = new java.util.Date().getTime(); // // 每隔CHECK_WAIT_CLIENT_RESPONSE_DELTA_TIME时间轮询一次 // try { // Thread.sleep(CHECK_WAIT_CLIENT_RESPONSE_DELTA_TIME); // } catch (InterruptedException e) { // e.printStackTrace(); // } // // 对每个用户进行检查 // // Debug.log(new String[] { "ServerModel", // // "CheckWaitClientResponseThread" }, "开始检测等待客户端未回复列表,共 " // // + waitClientRepTable.size() + " 个等待!"); // Iterator iterator = waitClientRepTable.keySet().iterator(); // synchronized (waitClientRepTable) { // while (iterator.hasNext()) { // key = iterator.next().toString(); // waitObj = waitClientRepTable.get(key); // // System.err.println("key : " + key + " size: " + // // waitClientRepTable.size() + " obj=null : " + // // (waitObj == null)); // if (waitObj == null) // continue; // // // System.err.println(currentTime - waitObj.time); // if ((currentTime - waitObj.time) > WAIT_CLIENT_RESPONSE_TIMEOUT) { // // 超时,重发 // Debug.log("ServerModel", "Wait for Client(" + // waitObj.ioSession.getRemoteAddress() // + ") response timeout!"); // // 不在线,调用删前回调,删除 // try { // clientUser = // clientUserIpTable.get(ServerModel.getIoSessionKey(waitObj.ioSession)); // } catch (NoIpException e) { // // e.printStackTrace(); // } // if (clientUser == null || !clientUser.onLine) { // Debug.log("ServerModel", "Client(" + waitObj.ioSession.getRemoteAddress() // + ") was offline,now delete it!"); // if (waitObj.waitClientResponseCallBack != null) // waitObj.waitClientResponseCallBack.beforeDelete(); // waitClientRepTable.remove(key); // continue; // } // // 重发,重置等待时间 // Debug.log("ServerModel", "Client(" + waitObj.ioSession.getRemoteAddress() // + ") online,send again!"); // serverNetwork.sendMessageToClient(waitObj.ioSession, // waitObj.messageHasSent); // waitObj.time = currentTime; // } // } // } // } // } // } }