实现一台主机(相当于服务器Server) 多台副机(Client)之间相互通讯
1 Client 思考问题 长连接如何保活(心跳线程 每隔1分钟发送一个心跳包到Server端 最后一次记录心跳的时间 根据心跳时间来判断线程是否存活)
2 Server 如何处理链路问题(轮询去除已经断开连接的副机子)
开启一个子线程 每隔6分钟检测一次 如果和副机子断开连接了 从缓存中去除掉副机
实现Server端
1 ServerSocket监听指定的端口
try { ServerSocket serverSocket = new ServerSocket(); serverSocket.setReuseAddress(true); serverSocket.bind(new InetSocketAddress(port)); Log.d("server", " port---->" + port); while (!callFinish) { Log.d("server", "server runing"); Socket socket = serverSocket.accept(); receiveClient(socket); } } catch (IOException e) { e.printStackTrace(); }
2 Server处理链路问题 移除已经失效的Client客户端
private void initClientCheck() { if (handlerThread == null) { handlerThread = new HandlerThread("ALPServerLoop") { @Override public void run() { super.run(); while (!callFinish) { try { //Thread.sleep(6 * 60 * 1000); Thread.sleep(10 * 1000); Log.d("server", "server 链路每过10秒检查一次"); } catch (InterruptedException e) { e.printStackTrace(); } List<ClientHandler> clientHandlers = new ArrayList<>(); clientHandlers.addAll(clientList); for (ClientHandler clientHandler : clientHandlers) { //客户端终止了 或者心跳时间超过6分钟 if (clientHandler.isFinish) { Log.d("server", "server检测到 客户端断开连接了 "); clientHandler.callStop(); synchronized (Server.this) { Log.d("server", "server检测到 客户端断开连接了 移除客户端 --->" + clientHandler.getName()); clientList.remove(clientHandler); } } } } } }; handlerThread.start(); } }
Server完整代码
public class Server { /** * 客户端列表 */ private List<ClientHandler> clientList = new ArrayList<>(); /** * 手动终止服务 * 包括终止该服务所有的子线程 */ private boolean callFinish = false; protected Server() { } public void init(int port) { initClientCheck(); try { ServerSocket serverSocket = new ServerSocket(); serverSocket.setReuseAddress(true); serverSocket.bind(new InetSocketAddress(port)); Log.d("server", " port---->" + port); while (!callFinish) { Log.d("server", "server runing"); Socket socket = serverSocket.accept(); receiveClient(socket); } } catch (IOException e) { e.printStackTrace(); } } /** * 链路检查 * 1 移除已经断开连接的副机子 * 2 移除6分钟没有收到心跳包的副机子(副机子没1分钟保持一次心跳) */ private HandlerThread handlerThread; private void initClientCheck() { if (handlerThread == null) { handlerThread = new HandlerThread("ALPServerLoop") { @Override public void run() { super.run(); while (!callFinish) { try { //Thread.sleep(6 * 60 * 1000); Thread.sleep(10 * 1000); Log.d("server", "server 链路每过10秒检查一次"); } catch (InterruptedException e) { e.printStackTrace(); } List<ClientHandler> clientHandlers = new ArrayList<>(); clientHandlers.addAll(clientList); for (ClientHandler clientHandler : clientHandlers) { //客户端终止了 或者心跳时间超过6分钟 if (clientHandler.isFinish) { Log.d("server", "server检测到 客户端断开连接了 "); clientHandler.callStop(); synchronized (Server.this) { Log.d("server", "server检测到 客户端断开连接了 移除客户端 --->" + clientHandler.getName()); clientList.remove(clientHandler); } } } } } }; handlerThread.start(); } } /** * 收到链路创建的请求 * * @param client Socket */ private void receiveClient(Socket client) { Log.d("server", "Server receiveClient " + String.format("开始监听客户端: %s", client.getRemoteSocketAddress())); ClientHandler clientHandler = new ClientHandler(client); synchronized (Server.this) { Log.d("server", "ClientHandler created " + clientHandler.getName()); clientList.add(clientHandler); } clientHandler.setName("ClientHandler" + client.getInetAddress()); clientHandler.start(); //clientHandler.lastBeating = SystemClock.elapsedRealtime(); } //相当于Client 只是继承了Thread 实现什么功能呢 private class ClientHandler extends Thread { private Socket socket; private InputStream inputStream; private OutputStream outputStream; private boolean callStop = false; private boolean isFinish = false; public ClientHandler(Socket socket) { this.socket = socket; } @Override public void run() { super.run(); init(); while (!callStop) { try { if (inputStream == null) { break; } int len = 0; byte[] bytes = new byte[inputStream.available()]; while ((len = inputStream.read(bytes)) != -1) { Log.d("server", new String(bytes)); } } catch (IOException e) { e.printStackTrace(); } } Log.d("server","ClientHandler 断开连接了 "); isFinish = true; } private void init() { try { inputStream = socket.getInputStream(); outputStream = socket.getOutputStream(); } catch (IOException e) { e.printStackTrace(); } } private void pushMsg(String msg) { try { byte[] bytesInfo = msg.getBytes(); if (outputStream != null) { Log.d("server", "server write msg -->" + msg); outputStream.write(bytesInfo); outputStream.flush(); } } catch (IOException e) { e.printStackTrace(); callStop(); } } public void callStop() { try { if (inputStream != null) { inputStream.close(); } if (outputStream != null) { outputStream.close(); } } catch (IOException e) { e.printStackTrace(); } inputStream = null; outputStream = null; callStop = true; isFinish = true; } } /** * 服务器推送消息到客户端 * * @param msg */ public void pushMsgToAll(String msg) { for (ClientHandler clientHandler : clientList) { clientHandler.pushMsg(msg); } } /** * 结束掉当前的服务器 */ public void finish() { clientList.clear(); //keyClient.clear(); callFinish = true; } }
2 PushServer 对Server进一步封装
public class PushServer { private Server server; private Thread workingThread; public static PushServer pushServer = new PushServer(); private PushServer() { init(); } private Handler pushServerHandler = null; private void init() { HandlerThread thread = new HandlerThread("ClientHeartBeatingThread") { @Override protected void onLooperPrepared() { super.onLooperPrepared(); pushServerHandler = new Handler(Looper.myLooper()) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; } }; thread.start(); } public void startServer(final int port) { workingThread = new Thread(new Runnable() { @Override public void run() { Log.d("pushServer", "开启Server"); server = new Server(); server.init(port); } }); workingThread.setName("PushServerWorking"); workingThread.start(); } /** * 推送消息到所有站点 * * @param msg String | 消息体 */ public void pushMsg(final String msg) { pushServerHandler.post(new Runnable() { @Override public void run() { if (server == null) { return; } server.pushMsgToAll(msg); } }); } public void finishServer() { if (server != null) { Log.d("pushServer", "server finish"); server.finish(); } try { if (workingThread != null && workingThread.isInterrupted() && workingThread.isAlive()) { Log.d("pushServer", "workingThread interrupt" + workingThread.getName()); workingThread.interrupt(); } } catch (Exception e) { e.printStackTrace(); } } }
3 Client实现
客户端开始连接 注意点 Client和Server端在同一个网端下 并且监听的是同一个端口 startConnect里面开启了一个死循环一直等待读取Server反馈的信息
/** * 客户端开始连接 * @param address * @param port */ public void startConnect(String address, int port) { try { socket = new Socket(); socket.connect(new InetSocketAddress(address, port), 3000); socket.setKeepAlive(true); inputStream = socket.getInputStream(); outputStream = socket.getOutputStream(); while (!callFinish){ read(); } Log.d("clinet","address--->"+address+ " port---->" +port); } catch (IOException e) { e.printStackTrace(); } }
4 pushClient 对Client进一步封装 实现心跳包保活机制 实现网络监听 后期实现该功能
public class PushClient { String address; int port; private Client client; public void startClient(String address, int port) { this.address = address; this.port = port; connect(); } public void connect() { disConnect(); Thread workingThread = new Thread(new Runnable() { @Override public void run() { client = new Client(); client.startConnect(address, port); } }); workingThread.setName("PushClientWorking_" + System.currentTimeMillis()); workingThread.start(); } /** * 断开本地的Socket连接 */ private synchronized void disConnect() { if (client != null) { client.close(); } } /** * 推送消息到服务器 * @param msg */ public void pushMsg(String msg) { if (client != null) { client.pushMsgToServer(msg); } } }