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<SocketRequest> mMessageQueue = new LinkedBlockingDeque<>();
|
|
private final ArrayMap<String, SendListener> 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();
|
}
|
}
|