package com.hdl.sdk.socket; import android.text.TextUtils; import android.util.Log; import androidx.collection.ArrayMap; import com.hdl.sdk.common.utils.ThreadToolUtils; import com.hdl.sdk.socket.annotation.ConnectStatus; import com.hdl.sdk.socket.client.IClient; import com.hdl.sdk.socket.listener.SendListener; import java.net.ConnectException; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** * Created by Tong on 2021/9/26. * Tcp/Udp 启动器 */ public class SocketBoot { private ExecutorService connectThread; private ScheduledExecutorService heartbeatThread; private ExecutorService sendThread; private ExecutorService receiveThread; private ScheduledExecutorService delayThread; private final IClient client; /** * socket是否在运行 */ private final AtomicBoolean isRun = new AtomicBoolean(false); private final AtomicBoolean isOpenRetry = new AtomicBoolean(false); private final AtomicInteger resendCount = new AtomicInteger(0); private final BlockingQueue mMessageQueue = new LinkedBlockingDeque<>(); private final ArrayMap sendMap = new ArrayMap<>(); public SocketBoot(IClient client) { this.client = client; } public ScheduledExecutorService getHeartBeat() { if (heartbeatThread == null) { heartbeatThread = ThreadToolUtils.getInstance().newScheduledThreadPool(1); } return heartbeatThread; } public void connect() { resendCount.set(0); resetConnect(true); isOpenRetry.set(true); } public synchronized void resetConnect(boolean isFirst) { final int maxRetry = client.getOptions().getMaxRetry(); if (maxRetry == 0 && resendCount.get() > 0 || (maxRetry > 0 && maxRetry + 1 < resendCount.get())) { Log.d("====", "===重连次数达到最大=="); return; } if (!client.isConnect()) { if (connectThread == null) { connectThread = ThreadToolUtils.getInstance().newFixedThreadPool(1); } connectThread.execute(new Runnable() { @Override public void run() { client.onConnectStatus(ConnectStatus.CONNECTING); if (!isFirst) { try { resendCount.set(resendCount.get() + 1); Thread.sleep(300L); Log.d("====", "==重连第" + resendCount + "次=="); } catch (Exception ignored) { } } try { client.connect(); isRun.set(true); if (client.isConnect()) { Log.d("====", "====连接成功===="); startHeartbeat(); initSendThread(); initReceiveThread(); client.onConnectStatus(ConnectStatus.CONNECTED); resendCount.set(0); } else { throw new ConnectException(); } } catch (Exception e) { e.printStackTrace(); Log.d("====", "===连接失败===" + e); //再判断一下有没有连接 if (!client.isConnect()) { isRun.set(false); client.onConnectStatus(ConnectStatus.DISCONNECT); stopHeartbeat(); disconnectError(); } } } }); } } public void initSendThread() { if (sendThread == null) { sendThread = ThreadToolUtils.getInstance().newFixedThreadPool(1); } sendThread.execute(new Runnable() { @Override public void run() { while (isRun.get()) { if (client.isConnect()) { Log.d("=====", "==发送数据=="); try { SocketRequest socketRequest = mMessageQueue.take(); final String action = socketRequest.getAction(); try { client.sendMsg(socketRequest.getData()); if (!TextUtils.isEmpty(action)) { SendListener sendListener = sendMap.get(action); if (sendListener != null) { sendListener.onSucceed(); } } } catch (Exception e) { if (!TextUtils.isEmpty(action)) { SendListener sendListener = sendMap.get(action); if (sendListener != null) { sendListener.onError(); } } stopHeartbeat(); if (sendThread != null) { sendThread.shutdownNow(); } if (isRun.get()) { disconnectError(); } } } catch (InterruptedException ignored) { } } } Log.d("=====", "==发送线程关闭=="); } }); } public void initReceiveThread() { if (receiveThread == null) { receiveThread = ThreadToolUtils.getInstance().newFixedThreadPool(1); } receiveThread.execute(new Runnable() { @Override public void run() { while (isRun.get()) { if (client.isConnect()) { try { //读取数据 client.onHandleResponse(); } catch (Exception e) { e.printStackTrace(); Log.d("====", "断开连接" + e.getMessage()); disconnectError(); } } } } }); } public void startHeartbeat() { if (heartbeatThread != null) { heartbeatThread.shutdownNow(); heartbeatThread = null; } if (client.getOptions() == null || client.getOptions().getHeartbeatTimeInterval() <= 0 || !client.getOptions().isEnabledHeartbeat()) { return; } getHeartBeat().scheduleWithFixedDelay(new Runnable() { @Override public void run() { if (isRun.get()) { Log.d("====", "===发送心跳包==="); if (client.getOptions() != null) { final byte[] heartBeat = client.getOptions().getHeartbeatData(); if (heartBeat != null) { sendMsg(heartBeat, false, null); } else { sendMsg(new byte[0], false, null); } } } } }, client.getOptions().getHeartbeatTimeInterval(), client.getOptions().getHeartbeatTimeInterval(), TimeUnit.MILLISECONDS); } public void stopHeartbeat() { if (heartbeatThread != null) { heartbeatThread.shutdownNow(); heartbeatThread = null; } } public void sendMsg(byte[] msg) { sendMsg(msg, true, null); } public void sendMsg(byte[] msg, SendListener listener) { sendMsg(msg, true, listener); } /** * @param listener 一般情况无需监听 */ private void sendMsg(byte[] msg, boolean isRefreshRetry, SendListener listener) { if (isRefreshRetry) { //重置连接次数 resendCount.set(0); } try { SocketRequest request = new SocketRequest(msg); if (listener != null && !TextUtils.isEmpty(request.getAction())) { sendMap.put(request.getAction(), listener); } mMessageQueue.put(request); } catch (InterruptedException ignored) { } if (!client.isConnect()) { resetConnect(false); } } /** * 发生错误,重连 */ private void disconnectError() { disconnect(); isRun.set(false); if (isOpenRetry.get()) { if (delayThread != null) { delayThread.shutdownNow(); } delayThread = ThreadToolUtils.getInstance().newScheduledThreadPool(1); delayThread.schedule(new Runnable() { @Override public void run() { if (!client.isConnect() && isOpenRetry.get()) { resetConnect(false); } } }, 3000, TimeUnit.MILLISECONDS); } } private synchronized void disconnect() { if (client.isConnect()) { client.disconnect(); //断开连接 client.onConnectStatus(ConnectStatus.DISCONNECT); } } public synchronized void close() { isOpenRetry.set(false); isRun.set(false); if (connectThread != null) { connectThread.shutdownNow(); connectThread = null; } if (heartbeatThread != null) { heartbeatThread.shutdownNow(); heartbeatThread = null; } if (sendThread != null) { sendThread.shutdownNow(); sendThread = null; } if (receiveThread != null) { receiveThread.shutdownNow(); receiveThread = null; } sendMap.clear(); client.disconnect(); mMessageQueue.clear(); } public synchronized void release() { close(); if (client != null && client.getOptions() != null) { client.getOptions().clearConnectStatusListener(); } } public boolean isConnect() { return client.isConnect(); } }