zuoxiao
2024-03-04 4d2d9239d8915a030bb84cb2147774470b04bf27
先上传Socket通讯相关代码
密码卡相关代码
10个文件已修改
61个文件已添加
4729 ■■■■■ 已修改文件
app/build.gradle 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/AndroidManifest.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/HomeActivity.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/ParameterActivity.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/SysActivity.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/card/PassWordCard.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/card/RegionCard.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_admin.xml 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_parameter.xml 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/build.gradle 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/AndroidManifest.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/ConnectionHolder.java 138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/EasySocket.java 340 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/callback/ProgressDialogCallBack.java 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/callback/SimpleCallBack.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/callback/SuperCallBack.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/config/CallbackIDFactory.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/config/DefaultMessageProtocol.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/config/DefaultX509ProtocolTrustManager.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/config/EasySocketOptions.java 478 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/config/SocketFactory.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/config/SocketSSLConfig.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/action/IOAction.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/action/SocketAction.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/action/SocketStatus.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/connect/SuperConnection.java 356 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/connect/TcpConnection.java 141 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/dispatcher/CallbackResponseDispatcher.java 191 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/dispatcher/MainThreadExecutor.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/dispatcher/SocketActionDispatcher.java 221 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/heartbeat/HeartManager.java 181 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/iowork/EasyReader.java 337 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/iowork/EasyWriter.java 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/iowork/IOManager.java 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/reconnect/AbsReconnection.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/reconnect/DefaultReConnection.java 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/entity/OriginReadData.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/entity/SocketAddress.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/entity/basemsg/IResponse.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/entity/basemsg/ISender.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/entity/basemsg/SuperCallbackResponse.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/entity/basemsg/SuperCallbackSender.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/entity/basemsg/SuperSender.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/exception/InitialExeption.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/exception/NotNullException.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/exception/ReadRecoverableExeption.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/exception/ReadUnrecoverableException.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/exception/RequestCancelException.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/exception/RequestTimeOutException.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/callback/ICallBack.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/callback/IProgressDialog.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/callback/IType.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/callback/ProgressCancelListener.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/config/IConnectionSwitchListener.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/config/IMessageProtocol.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/config/IOptions.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/conn/IConnectionManager.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/conn/IHeartManager.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/conn/IReconnListener.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/conn/ISend.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/conn/ISocketActionDispatch.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/conn/ISocketActionListener.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/conn/ISubscribeSocketAction.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/conn/SocketActionListener.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/io/IIOManager.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/io/IReader.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/interfaces/io/IWriter.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/utils/HexUtil.java 275 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/utils/LogUtil.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/utils/Utils.java 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
settings.gradle 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/build.gradle
@@ -75,7 +75,7 @@
    implementation 'com.wang.avi:library:2.1.3'
    //地址选择
    implementation project(':pickerviewlibrary')
    implementation project(':easysocket')
    implementation 'com.tencent.bugly:crashreport:latest.release'
//    处理图片
//    implementation (name: 'ocr-library', ext: 'aar')
app/src/main/AndroidManifest.xml
@@ -116,6 +116,7 @@
        <activity android:name=".activity.IdentifyingActivity" />
        <activity android:name=".activity.ReplacementActivity" />
        <activity android:name=".activity.RechargeDetail" />
        <activity android:name=".activity.PasswordCardActivity" />
        <meta-data
app/src/main/java/com/dayu/recharge/activity/HomeActivity.java
@@ -79,6 +79,7 @@
                startActivity(new Intent(HomeActivity.this, ReadCardAcitivy.class));
            }
        });
        //管理系统界面
        homeBinding.homeAdmin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
app/src/main/java/com/dayu/recharge/activity/ParameterActivity.java
@@ -57,5 +57,13 @@
                startActivity(intent);
            }
        });
        //密码卡设置密码
        binding.parameterPassWordCard.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(ParameterActivity.this, PasswordCardActivity.class);
                startActivity(intent);
            }
        });
    }
}
app/src/main/java/com/dayu/recharge/activity/SysActivity.java
@@ -11,10 +11,12 @@
import com.dayu.recharge.card.ConfigureDeviceRegistrationCrad;
import com.dayu.recharge.card.DomainCard;
import com.dayu.recharge.card.ManageCard;
import com.dayu.recharge.card.PassWordCard;
import com.dayu.recharge.card.RegisteredCard;
import com.dayu.recharge.card.TestCard;
import com.dayu.recharge.databinding.ActivityAdminBinding;
import com.dayu.recharge.dbBean.DomainBean;
import com.dayu.recharge.dbBean.PassWordCardBean;
import com.dayu.recharge.dbBean.PowerBean;
import com.dayu.recharge.utils.TipUtil;
@@ -99,6 +101,8 @@
                startActivity(intent);
            }
        });
        //制作测试卡
        adminBinding.adminTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
@@ -108,6 +112,8 @@
                startActivity(intent);
            }
        });
        //制作配置设备信息卡
        adminBinding.adminConfigDeviceRegistration.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
@@ -118,6 +124,7 @@
            }
        });
        //制作配置水泵功率卡
        adminBinding.adminConfigPower.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
@@ -135,6 +142,30 @@
            }
        });
        adminBinding.adminPassWordCard.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                PassWordCardBean powerBean = baseDao.passWordCardDao().findFirst();
                if (powerBean != null) {
                    Intent intent = new Intent(SysActivity.this, NFCWreatActivity.class);
                    PassWordCard passWordCard = new PassWordCard();
                    passWordCard.setPassWord(powerBean.getPassWord());
                    intent.putExtra("passWordCard", passWordCard);
                    startActivity(intent);
                } else {
                    TipUtil.show("请先设置卡密码");
                }
            }
        });
        //制作区域表号卡
        adminBinding.adminRegionCard.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            }
        });
    }
app/src/main/java/com/dayu/recharge/card/PassWordCard.java
@@ -3,20 +3,27 @@
import com.dayu.recharge.tools.HexUtil;
import com.dayu.recharge.utils.MyCommon;
import java.io.Serializable;
import java.util.List;
/**
 * Copyright (C), 2023,
 * Copyright (C), 2024,
 * Author: zuo
 * Date: 2023-11-08 11:22
 * Date: 2024-3-04 11:22
 * Description:密码卡
 */
public class PassWordCard {
public class PassWordCard implements Serializable {
    public String cardType = MyCommon.PASS_WORD_CRAD_TYPE;//卡类型
    public String cardData = "A0B1C289";//标识码
    public String passWord;//六位的密码
    public String getPassWord() {
        return passWord;
    }
    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }
    public static PassWordCard getBean(List<byte[]> data){
app/src/main/java/com/dayu/recharge/card/RegionCard.java
@@ -10,7 +10,7 @@
 * author: zuo
 * Date: 2024-02-29
 * Time: 16:29
 * 备注:区域标号卡
 * 备注:区域表号卡
 */
public class RegionCard implements Serializable {
app/src/main/res/layout/activity_admin.xml
@@ -52,6 +52,7 @@
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:padding="5dp"
                android:visibility="gone"
                android:text="制作重新注册设备卡"
                android:textColor="@color/text_selecter"
                android:textSize="@dimen/text_size" />
@@ -63,6 +64,7 @@
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:padding="5dp"
                android:visibility="gone"
                android:text="制作删除全部用户卡"
                android:textColor="@color/text_selecter"
                android:textSize="@dimen/text_size" />
@@ -75,6 +77,7 @@
                android:layout_marginTop="20dp"
                android:padding="5dp"
                android:text="制作设置域名卡"
                android:visibility="gone"
                android:textColor="@color/text_selecter"
                android:textSize="@dimen/text_size" />
@@ -87,6 +90,7 @@
                android:layout_marginTop="20dp"
                android:padding="5dp"
                android:text="制作测试卡"
                android:visibility="gone"
                android:textColor="@color/text_selecter"
                android:textSize="@dimen/text_size" />
@@ -98,6 +102,18 @@
                android:layout_marginTop="20dp"
                android:padding="5dp"
                android:text="制作配置设备信息卡"
                android:visibility="gone"
                android:textColor="@color/text_selecter"
                android:textSize="@dimen/text_size" />
            <TextView
                android:id="@+id/admin_passWordCard"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:padding="5dp"
                android:text="制作密码卡"
                android:textColor="@color/text_selecter"
                android:textSize="@dimen/text_size" />
@@ -111,6 +127,28 @@
                android:text="制作配置水泵功率卡"
                android:textColor="@color/text_selecter"
                android:textSize="@dimen/text_size" />
            <TextView
                android:id="@+id/admin_blackCard"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:padding="5dp"
                android:text="制作黑卡"
                android:textColor="@color/text_selecter"
                android:textSize="@dimen/text_size" />
            <TextView
                android:id="@+id/admin_regionCard"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:padding="5dp"
                android:text="制作区域表号卡"
                android:textColor="@color/text_selecter"
                android:textSize="@dimen/text_size" />
        </LinearLayout>
app/src/main/res/layout/activity_parameter.xml
@@ -20,6 +20,7 @@
        android:layout_marginLeft="20dp"
        android:layout_marginTop="20dp"
        android:padding="5dp"
        android:visibility="gone"
        android:text="域名卡设置"
        android:textColor="@color/text_selecter"
        android:textSize="@dimen/text_size" />
@@ -31,6 +32,7 @@
        android:layout_marginLeft="20dp"
        android:layout_marginTop="20dp"
        android:padding="5dp"
        android:visibility="gone"
        android:text="水泵功率卡设置"
        android:textColor="@color/text_selecter"
        android:textSize="@dimen/text_size" />
@@ -46,7 +48,16 @@
        android:text="电量单价设置"
        android:textColor="@color/text_selecter"
        android:textSize="@dimen/text_size" />
    <TextView
        android:id="@+id/parameter_PassWordCard"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="20dp"
        android:padding="5dp"
        android:text="电量单价设置"
        android:textColor="@color/text_selecter"
        android:textSize="@dimen/text_size" />
    <TextView
        android:id="@+id/parameter_cardIdentifying"
        android:layout_width="match_parent"
@@ -55,6 +66,7 @@
        android:layout_marginTop="20dp"
        android:padding="5dp"
        android:text="卡标识码设置"
        android:visibility="gone"
        android:textColor="@color/text_selecter"
        android:textSize="@dimen/text_size" />
easysocket/build.gradle
New file
@@ -0,0 +1,29 @@
apply plugin: 'com.android.library'
android {
    compileSdkVersion 27
    //buildToolsVersion rootProject.ext.android.buildToolsVersion
    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
//        javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true } }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    compileOnly 'com.google.code.gson:gson:2.2.4'
}
sourceCompatibility = "7"
targetCompatibility = "7"
easysocket/src/main/AndroidManifest.xml
New file
@@ -0,0 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.socket" >
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
easysocket/src/main/java/com/easysocket/ConnectionHolder.java
New file
@@ -0,0 +1,138 @@
package com.easysocket;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.connection.connect.SuperConnection;
import com.easysocket.connection.connect.TcpConnection;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.config.IConnectionSwitchListener;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.utils.LogUtil;
import java.util.HashMap;
import java.util.Map;
/**
 * Author:Alex
 * Date:2019/6/4
 * Note:socket连接管理器
 */
public class ConnectionHolder {
    private volatile Map<String, IConnectionManager> mConnectionManagerMap = new HashMap<>();
    private static class InstanceHolder {
        private static final ConnectionHolder INSTANCE = new ConnectionHolder();
    }
    public static ConnectionHolder getInstance() {
        return InstanceHolder.INSTANCE;
    }
    private ConnectionHolder() {
        mConnectionManagerMap.clear();
    }
    /**
     * 移除某个连接
     *
     * @param socketAddress
     */
    public void removeConnection(SocketAddress socketAddress) {
        removeConnection(createKey(socketAddress));
    }
    public void removeConnection(String socketAddress) {
        mConnectionManagerMap.remove(socketAddress);
    }
    /**
     * 获取指定SocketAddress的连接,参数配置使用默认的
     *
     * @param address
     * @return
     */
    public IConnectionManager getConnection(SocketAddress address) {
        return getConnection(createKey(address));
    }
    public IConnectionManager getConnection(String address) {
        IConnectionManager manager = mConnectionManagerMap.get(address);
        if (manager == null) {
            return getConnection(address, EasySocketOptions.getDefaultOptions());
        } else {
            return getConnection(address, manager.getOptions());
        }
    }
    /**
     * 获取指定SocketAddress的连接
     *
     * @param address
     * @param socketOptions
     * @return
     */
    public IConnectionManager getConnection(SocketAddress address, EasySocketOptions socketOptions) {
        return getConnection(createKey(address),socketOptions);
    }
    public IConnectionManager getConnection(String address, EasySocketOptions socketOptions) {
        IConnectionManager manager = mConnectionManagerMap.get(address);
        if (manager != null) { // 有缓存
            manager.setOptions(socketOptions);
            return manager;
        } else {
            return createNewManagerAndCache(address, socketOptions);
        }
    }
    /**
     * 创建新的连接并缓存
     *
     * @param address
     * @param socketOptions
     * @return
     */
    private IConnectionManager createNewManagerAndCache(SocketAddress address, EasySocketOptions socketOptions) {
        SuperConnection manager = new TcpConnection(address); // 创建连接管理器
        manager.setOptions(socketOptions); // 设置参数
        // 连接主机的切换监听
        manager.setOnConnectionSwitchListener(new IConnectionSwitchListener() {
            @Override
            public void onSwitchConnectionInfo(IConnectionManager manager, SocketAddress oldAddress,
                                               SocketAddress newAddress) {
                // 切换了另外一个主机的连接,删除旧的连接和添加新的连接
                synchronized (mConnectionManagerMap) {
                    // 首先断开连接,销毁相关线程和资源
                    LogUtil.d("---> 首先断开连接,销毁相关线程和资源");
                    mConnectionManagerMap.get(createKey(oldAddress)).disconnect(false);
                    mConnectionManagerMap.remove(createKey(oldAddress));
                    mConnectionManagerMap.put(createKey(newAddress), manager);
                }
            }
        });
        synchronized (mConnectionManagerMap) {
            mConnectionManagerMap.put(createKey(address), manager);
        }
        return manager;
    }
    private IConnectionManager createNewManagerAndCache(String address, EasySocketOptions socketOptions) {
        return createNewManagerAndCache(createSocketAddress(address), socketOptions);
    }
    /**
     * @param socketAddress
     * @return
     */
    private String createKey(SocketAddress socketAddress) {
        return socketAddress.getIp() + ":" + socketAddress.getPort();
    }
    private SocketAddress createSocketAddress(String address) {
        String[] s = address.split(":");
        return new SocketAddress(s[0], Integer.parseInt(s[1]));
    }
}
easysocket/src/main/java/com/easysocket/EasySocket.java
New file
@@ -0,0 +1,340 @@
package com.easysocket;
import android.content.Context;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.connection.heartbeat.HeartManager;
import com.easysocket.entity.SocketAddress;
import com.easysocket.entity.basemsg.SuperCallbackSender;
import com.easysocket.exception.InitialExeption;
import com.easysocket.exception.NotNullException;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.ISocketActionListener;
import com.easysocket.utils.LogUtil;
import java.nio.charset.Charset;
/**
 * Author:Alex
 * Date:2019/6/4
 * Note:EasySocket API
 */
public class EasySocket {
    /**
     * 连接的缓存
     */
    private static ConnectionHolder connectionHolder = ConnectionHolder.getInstance();
    // 单例
    private volatile static EasySocket singleton = null;
    /**
     * 默认的连接参数
     */
    private EasySocketOptions defOptions;
    /**
     * 默认的连接
     */
    private IConnectionManager defConnection;
    /**
     * 上下文
     */
    private Context context;
    /**
     * 单例
     *
     * @return
     */
    public static EasySocket getInstance() {
        if (singleton == null) {
            synchronized (EasySocket.class) {
                if (singleton == null) {
                    singleton = new EasySocket();
                }
            }
        }
        return singleton;
    }
    /**
     * 获取上下文
     *
     * @return
     */
    public Context getContext() {
        return context;
    }
    /**
     * 获取默认的配置参数
     *
     * @return
     */
    public EasySocketOptions getDefOptions() {
        return defOptions == null ? EasySocketOptions.getDefaultOptions() : defOptions;
    }
    /**
     * 创建socket连接,此连接为默认的连接,如果你的项目只有一个Socket连接,可以用这个方法,
     * 在方法不指定连接地址的情况下,默认使用都是这个连接,
     * 比如: upMessage(byte[] message)、 connect()等
     *
     * @return
     */
    public EasySocket createConnection(EasySocketOptions options, Context context) {
        this.defOptions = options;
        this.context = context;
        SocketAddress socketAddress = options.getSocketAddress();
        if (options.getSocketAddress() == null) {
            throw new InitialExeption("请在初始化的时候设置SocketAddress");
        }
        // 如果有备用主机则设置
        if (options.getBackupAddress() != null) {
            socketAddress.setBackupAddress(options.getBackupAddress());
        }
        if (defConnection == null) {
            defConnection = connectionHolder.getConnection(socketAddress,
                    options == null ? EasySocketOptions.getDefaultOptions() : options);
            // 执行连接
            defConnection.connect();
        }
        return this;
    }
    /**
     * 连接socket,作用于默认连接
     *
     * @return
     */
    public EasySocket connect() {
        getDefconnection().connect();
        return this;
    }
    /**
     * @param address socket地址,包括ip和端口
     * @return
     */
    public EasySocket connect(String address) {
        getConnection(address).connect();
        return this;
    }
    /**
     * 关闭连接,作用于默认连接
     *
     * @param isNeedReconnect 是否需要重连
     * @return
     */
    public EasySocket disconnect(boolean isNeedReconnect) {
        LogUtil.d("EasySocket--》disconnect");
        getDefconnection().disconnect(isNeedReconnect);
        return this;
    }
    /**
     * 关闭连接
     *
     * @param isNeedReconnect 是否需要重连
     * @return
     */
    public EasySocket disconnect(String address, boolean isNeedReconnect) {
        getConnection(address).disconnect(isNeedReconnect);
        return this;
    }
    /**
     * 销毁连接对象,作用于默认连接
     *
     * @return
     */
    public EasySocket destroyConnection() {
        LogUtil.d("easysocket--》destroyConnection");
        // 断开连接
        getDefconnection().disconnect(false);
        // 移除连接
        connectionHolder.removeConnection(defOptions.getSocketAddress());
        defConnection = null;
        return this;
    }
    /**
     * 销毁连接对象
     *
     * @return
     */
    public EasySocket destroyConnection(String address) {
        // 断开连接
        getConnection(address).disconnect(false);
        // 移除连接
        connectionHolder.removeConnection(address);
        return this;
    }
    /**
     * 发送有回调的消息,作用于默认连接
     *
     * @param sender
     * @return
     */
    public IConnectionManager upCallbackMessage(SuperCallbackSender sender) {
        getDefconnection().upCallbackMessage(sender);
        return defConnection;
    }
    /**
     * 发送有回调的消息
     *
     * @param sender
     * @return
     */
    public IConnectionManager upCallbackMessage(SuperCallbackSender sender, String address) {
        return getConnection(address).upCallbackMessage(sender);
    }
    /**
     * 发送byte[]
     *
     * @param message
     * @return
     */
    public IConnectionManager upMessage(byte[] message, String address) {
        return getConnection(address).upBytes(message);
    }
    /**
     * 发送byte[],作用于默认连接
     *
     * @param message
     * @return
     */
    public IConnectionManager upMessage(byte[] message) {
        return getDefconnection().upBytes(message);
    }
    /**
     * 注册监听socket行为,作用于默认连接
     *
     * @param socketActionListener
     */
    public EasySocket subscribeSocketAction(ISocketActionListener socketActionListener) {
        getDefconnection().subscribeSocketAction(socketActionListener);
        return this;
    }
    /**
     * 注册监听socket行为
     *
     * @param socketActionListener
     */
    public EasySocket subscribeSocketAction(ISocketActionListener socketActionListener, String address) {
        getConnection(address).subscribeSocketAction(socketActionListener);
        return this;
    }
    /**
     * 开启心跳检测,作用于默认连接
     *
     * @param clientHeart
     * @return
     */
    public EasySocket startHeartBeat(byte[] clientHeart, HeartManager.HeartbeatListener listener) {
        getDefconnection().getHeartManager().startHeartbeat(clientHeart, listener);
        return this;
    }
    /**
     * 开启心跳检测
     *
     * @param clientHeart
     * @return
     */
    public EasySocket startHeartBeat(byte[] clientHeart, String address, HeartManager.HeartbeatListener listener) {
        getConnection(address).getHeartManager().startHeartbeat(clientHeart, listener);
        return this;
    }
    /**
     * 获取连接
     *
     * @return
     */
    public IConnectionManager getDefconnection() {
        if (defConnection == null) {
//            throw new NotNullException("你还没有创建:" + defOptions.getSocketAddress().getIp() + ":" + defOptions.getSocketAddress().getPort()
//                    + "的Socket的连接,请使用com.easysocket.EasySocket.connect()方法创建一个默认的连接");
        }
        return defConnection;
    }
    /**
     * 获取连接
     *
     * @return
     */
    public IConnectionManager getConnection(String address) {
        IConnectionManager connectionManager = connectionHolder.getConnection(address);
        if (connectionManager == null) {
            throw new NotNullException("请先创建:" + address + "的Socket连接");
        }
        return connectionManager;
    }
    /**
     * 创建指定的socket连接,如果你的项目有多个socket连接,可以用这个方法创建更多的连接,
     * 当你使用带有socket地址为参数的方法的时候,作用的就是对应的连接
     * 比如:connect(String address)、 upMessage(byte[] message, String address)等
     *
     * @param socketOptions
     * @return
     */
    public IConnectionManager createSpecifyConnection(EasySocketOptions socketOptions, Context context) {
        this.context = context;
        IConnectionManager connectionManager = connectionHolder.getConnection(socketOptions.getSocketAddress(), socketOptions == null
                ? EasySocketOptions.getDefaultOptions() : socketOptions);
        connectionManager.connect();
        return connectionManager;
    }
    /**
     * 获取指定的连接
     *
     * @param socketAddress
     * @return
     */
    public IConnectionManager getSpecifyConnection(String socketAddress) {
        return connectionHolder.getConnection(socketAddress);
    }
    /**
     * 发送消息至指定的连接
     *
     * @param sender
     * @param socketAddress
     */
    public IConnectionManager upToSpecifyConnection(byte[] sender, String socketAddress) {
        IConnectionManager connect = getSpecifyConnection(socketAddress);
        if (connect != null) {
            connect.upBytes(sender);
        }
        return connect;
    }
    /**
     * 是否为debug
     *
     * @param debug
     */
    public void setDebug(boolean debug) {
        EasySocketOptions.setIsDebug(debug);
    }
}
easysocket/src/main/java/com/easysocket/callback/ProgressDialogCallBack.java
New file
@@ -0,0 +1,116 @@
package com.easysocket.callback;
import android.app.Dialog;
import android.content.DialogInterface;
import com.easysocket.entity.OriginReadData;
import com.easysocket.exception.RequestCancelException;
import com.easysocket.interfaces.callback.IProgressDialog;
import com.easysocket.interfaces.callback.ProgressCancelListener;
/**
 * 自定义带有加载进度框的回调
 */
public abstract class ProgressDialogCallBack extends SuperCallBack implements ProgressCancelListener {
    private IProgressDialog progressDialog;
    private Dialog mDialog;
    private boolean isShowProgress = true;
    /**
     * @param
     */
    public ProgressDialogCallBack(IProgressDialog progressDialog, String callbackId) {
        super(callbackId);
        this.progressDialog = progressDialog;
        init(false);
        onStart();
    }
    /**
     * 自定义加载进度框,可以设置是否显示弹出框,是否可以取消
     *
     * @param progressDialog dialog
     * @param isShowProgress 是否显示进度
     * @param isCancel       对话框是否可以取消
     * @param
     */
    public ProgressDialogCallBack(IProgressDialog progressDialog, boolean isShowProgress,
                                  boolean isCancel, String callbackId) {
        super(callbackId);
        this.progressDialog = progressDialog;
        this.isShowProgress = isShowProgress;
        init(isCancel);
        onStart();
    }
    /**
     * 初始化
     *
     * @param isCancel
     */
    private void init(boolean isCancel) {
        if (progressDialog == null) return;
        mDialog = progressDialog.getDialog();
        if (mDialog == null) return;
        mDialog.setCancelable(isCancel);
        if (isCancel) {
            mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialogInterface) {
                    ProgressDialogCallBack.this.onCancelProgress();
                }
            });
        }
    }
    /**
     * 展示进度框
     */
    private void showProgress() {
        if (!isShowProgress) {
            return;
        }
        if (mDialog != null && !mDialog.isShowing()) {
            mDialog.show();
        }
    }
    /**
     * 取消进度框
     */
    private void dismissProgress() {
        if (!isShowProgress) {
            return;
        }
        if (mDialog != null && mDialog.isShowing()) {
            mDialog.dismiss();
        }
    }
    @Override
    public void onStart() {
        showProgress();
    }
    @Override
    public void onCompleted() {
        dismissProgress();
    }
    public abstract void onResponse(OriginReadData data);
    @Override
    public void onError(Exception e) {
        onCompleted();
    }
    @Override
    public void onCancelProgress() {
        onCompleted();
        onError(new RequestCancelException("网络请求被取消"));
    }
}
easysocket/src/main/java/com/easysocket/callback/SimpleCallBack.java
New file
@@ -0,0 +1,29 @@
package com.easysocket.callback;
/**
 * Created by LXR ON 2018/8/29.
 */
public abstract class SimpleCallBack extends SuperCallBack{
    public SimpleCallBack(String callbackId) {
        super(callbackId);
    }
    @Override
    public void onStart() {
    }
    @Override
    public void onCompleted() {
    }
    @Override
    public void onError(Exception e) {
    }
}
easysocket/src/main/java/com/easysocket/callback/SuperCallBack.java
New file
@@ -0,0 +1,44 @@
package com.easysocket.callback;
import com.easysocket.entity.OriginReadData;
/**
 * Created by LXR ON 2018/8/29.
 */
public abstract class SuperCallBack {
    /**
     * 随机字符串,识别服务端应答消息的唯一标识
     */
    private String callbackId;
    /**
     * @param callbackId 识别服务端应答消息的唯一标识
     */
    public SuperCallBack(String callbackId) {
        this.callbackId = callbackId;
    }
    /**
     * 获取回调ID
     *
     * @return
     */
    public String getCallbackId() {
        return callbackId;
    }
    public abstract void onStart();
    public abstract void onCompleted();
    public abstract void onError(Exception e);
    public void onSuccess(OriginReadData data) {
        onCompleted();
        onResponse(data);
    }
    public abstract void onResponse(OriginReadData data);
}
easysocket/src/main/java/com/easysocket/config/CallbackIDFactory.java
New file
@@ -0,0 +1,18 @@
package com.easysocket.config;
import com.easysocket.entity.OriginReadData;
/**
 * Author:Alex
 * Date:2019/6/4
 * Note:要想实现EasySocket的回调功能,必须实现此工厂类,callbackID作为回调消息的唯一标识
 */
public abstract class CallbackIDFactory {
    /**
     * 返回callbackID
     *
     * @param
     * @return 如果没有callbackID请返回null
     */
    public abstract String getCallbackID(OriginReadData data);
}
easysocket/src/main/java/com/easysocket/config/DefaultMessageProtocol.java
New file
@@ -0,0 +1,28 @@
package com.easysocket.config;
import com.easysocket.interfaces.config.IMessageProtocol;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
 * Author:Alex
 * Date:2019/5/31
 * Note:默认的消息协议,header为4个字节,保存消息体 body的长度
 */
public class DefaultMessageProtocol implements IMessageProtocol {
    @Override
    public int getHeaderLength() {
        return 4; // 包头长度,用来保存body的长度值
    }
    @Override
    public int getBodyLength(byte[] header, ByteOrder byteOrder) {
        if (header == null || header.length < getHeaderLength()) {
            return 0;
        }
        ByteBuffer bb = ByteBuffer.wrap(header);
        bb.order(byteOrder);
        return bb.getInt(); // body的长度以int的形式保存在 header
    }
}
easysocket/src/main/java/com/easysocket/config/DefaultX509ProtocolTrustManager.java
New file
@@ -0,0 +1,28 @@
package com.easysocket.config;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
/**
 * Author:Alex
 * Date:2019/6/3
 * Note:
 */
public class DefaultX509ProtocolTrustManager implements X509TrustManager {
    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }
    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }
    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
    }
}
easysocket/src/main/java/com/easysocket/config/EasySocketOptions.java
New file
@@ -0,0 +1,478 @@
package com.easysocket.config;
import com.easysocket.connection.reconnect.AbsReconnection;
import com.easysocket.connection.reconnect.DefaultReConnection;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.config.IMessageProtocol;
import java.nio.ByteOrder;
/**
 * Author:Alex。
 * Date:2019/5/31。
 * Note:socket相关配置。
 */
public class EasySocketOptions {
    /**
     * 是否调试模式
     */
    private static boolean isDebug = true;
    /**
     * 主机地址
     */
    private SocketAddress socketAddress;
    /**
     * 备用主机地址
     */
    private SocketAddress backupAddress;
    /**
     * 写入Socket管道的字节序
     */
    private ByteOrder writeOrder;
    /**
     * 从Socket读取字节时的字节序
     */
    private ByteOrder readOrder;
    /**
     * 从socket读取数据时遵从的数据包结构协议,在业务层进行定义
     */
    private IMessageProtocol messageProtocol;
    /**
     * 写数据时单个数据包的最大值
     */
    private int maxWriteBytes;
    /**
     * 读数据时单次读取最大缓存值,数值越大效率越高,但是系统消耗也越大
     */
    private int maxReadBytes;
    /**
     * 心跳频率/毫秒
     */
    private long heartbeatFreq;
    /**
     * 心跳最大的丢失次数,大于这个数据,将断开socket连接
     */
    private int maxHeartbeatLoseTimes;
    /**
     * 连接超时时间(毫秒)
     */
    private int connectTimeout;
    /**
     * 服务器返回数据的最大值(单位Mb),防止客户端内存溢出
     */
    private int maxResponseDataMb;
    /**
     * socket重连管理器
     */
    private AbsReconnection reconnectionManager;
    /**
     * 安全套接字相关配置
     */
    private SocketSSLConfig easySSLConfig;
    /**
     * socket工厂
     */
    private SocketFactory socketFactory;
    /**
     * 实现回调功能需要callbackID,而callbackID是保存在发送消息和应答消息中的,此工厂用来获取socket消息中
     * 保存callbackID值的key,比如json格式中的key-value中的key
     */
    private CallbackIDFactory callbackIDFactory;
    /**
     * 请求超时时间,单位毫秒
     */
    private long requestTimeout;
    /**
     * 是否开启请求超时检测
     */
    private boolean isOpenRequestTimeout;
    /**
     * IO字符流的编码方式,默认utf-8
     */
    private String charsetName;
    public boolean isDebug() {
        return isDebug;
    }
    /**
     * 静态内部类
     */
    public static class Builder {
        EasySocketOptions socketOptions;
        // 首先获得一个默认的配置
        public Builder() {
            this(getDefaultOptions());
        }
        public Builder(EasySocketOptions defaultOptions) {
            socketOptions = defaultOptions;
        }
        /**
         * 设置socket 主机地址
         *
         * @param socketAddress
         * @return
         */
        public Builder setSocketAddress(SocketAddress socketAddress) {
            socketOptions.socketAddress = socketAddress;
            return this;
        }
        /**
         * 设置备用的主机地址
         *
         * @param backupAddress
         * @return
         */
        public Builder setBackupAddress(SocketAddress backupAddress) {
            socketOptions.backupAddress = backupAddress;
            return this;
        }
        /**
         * 设置是否开启请求超时的检测
         *
         * @param openRequestTimeout
         * @return
         */
        public Builder setOpenRequestTimeout(boolean openRequestTimeout) {
            socketOptions.isOpenRequestTimeout = openRequestTimeout;
            return this;
        }
        /**
         * 设置请求超时时间
         *
         * @param requestTimeout 毫秒
         * @return
         */
        public Builder setRequestTimeout(long requestTimeout) {
            socketOptions.requestTimeout = requestTimeout;
            return this;
        }
        /**
         * 设置请求ack的工厂
         *
         * @param callbackIDFactory
         */
        public Builder setCallbackIDFactory(CallbackIDFactory callbackIDFactory) {
            socketOptions.callbackIDFactory = callbackIDFactory;
            return this;
        }
        /**
         * 设置写数据的字节顺序
         *
         * @param writeOrder
         * @return
         */
        public Builder setWriteOrder(ByteOrder writeOrder) {
            socketOptions.writeOrder = writeOrder;
            return this;
        }
        /**
         * 设置读数据的字节顺序
         *
         * @param readOrder
         * @return
         */
        public Builder setReadOrder(ByteOrder readOrder) {
            socketOptions.readOrder = readOrder;
            return this;
        }
        /**
         * 设置读取数据的数据结构协议
         *
         * @param readerProtocol
         * @return
         */
        public Builder setReaderProtocol(IMessageProtocol readerProtocol) {
            socketOptions.messageProtocol = readerProtocol;
            return this;
        }
        /**
         * 设置写数据时单个数据包的最大值
         *
         * @param maxWriteBytes
         * @return
         */
        public Builder setMaxWriteBytes(int maxWriteBytes) {
            socketOptions.maxWriteBytes = maxWriteBytes;
            return this;
        }
        /**
         * 设置读数据时单次读取的最大缓存值
         *
         * @param maxReadBytes
         * @return
         */
        public Builder setMaxReadBytes(int maxReadBytes) {
            socketOptions.maxReadBytes = maxReadBytes;
            return this;
        }
        /**
         * 设置心跳发送频率,单位毫秒
         *
         * @param heartbeatFreq
         * @return
         */
        public Builder setHeartbeatFreq(long heartbeatFreq) {
            socketOptions.heartbeatFreq = heartbeatFreq;
            return this;
        }
        /**
         * 设置心跳丢失的最大允许数,如果超过这个最大数就断开socket连接
         *
         * @param maxHeartbeatLoseTimes
         * @return
         */
        public Builder setMaxHeartbeatLoseTimes(int maxHeartbeatLoseTimes) {
            socketOptions.maxHeartbeatLoseTimes = maxHeartbeatLoseTimes;
            return this;
        }
        /**
         * 设置连接超时时间
         *
         * @param connectTimeout
         * @return
         */
        public Builder setConnectTimeout(int connectTimeout) {
            socketOptions.connectTimeout = connectTimeout;
            return this;
        }
        /**
         * 设置服务器返回数据的允许的最大值,单位兆
         *
         * @param maxResponseDataMb
         * @return
         */
        public Builder setMaxResponseDataMb(int maxResponseDataMb) {
            socketOptions.maxResponseDataMb = maxResponseDataMb;
            return this;
        }
        /**
         * 设置重连管理器
         *
         * @param reconnectionManager
         * @return
         */
        public Builder setReconnectionManager(AbsReconnection reconnectionManager) {
            socketOptions.reconnectionManager = reconnectionManager;
            return this;
        }
        /**
         * 安全套接字的配置
         *
         * @param easySSLConfig
         * @return
         */
        public Builder setEasySSLConfig(SocketSSLConfig easySSLConfig) {
            socketOptions.easySSLConfig = easySSLConfig;
            return this;
        }
        /**
         * 自定义创建socket工厂
         *
         * @param socketFactory
         * @return
         */
        public Builder setSocketFactory(SocketFactory socketFactory) {
            socketOptions.socketFactory = socketFactory;
            return this;
        }
        public Builder setCharsetName(String charsetName) {
            socketOptions.charsetName = charsetName;
            return this;
        }
        public EasySocketOptions build() {
            return socketOptions;
        }
    }
    /**
     * 获取默认的配置
     *
     * @return
     */
    public static EasySocketOptions getDefaultOptions() {
        EasySocketOptions options = new EasySocketOptions();
        options.socketAddress = null;
        options.backupAddress = null;
        options.heartbeatFreq = 5 * 1000;
        options.messageProtocol = null;
        options.maxResponseDataMb = 5;
        options.connectTimeout = 5 * 1000; // 连接超时默认5秒
        options.maxWriteBytes = 100;
        options.maxReadBytes = 50;
        options.readOrder = ByteOrder.BIG_ENDIAN;
        options.writeOrder = ByteOrder.BIG_ENDIAN;
        options.maxHeartbeatLoseTimes = 5;
        options.reconnectionManager = new DefaultReConnection();
        options.easySSLConfig = null;
        options.socketFactory = null;
        options.callbackIDFactory = null;
        options.requestTimeout = 10 * 1000; // 默认十秒
        options.isOpenRequestTimeout = true; // 默认开启
        options.charsetName = "UTF-8";
        return options;
    }
    public String getCharsetName() {
        return charsetName;
    }
    public ByteOrder getWriteOrder() {
        return writeOrder;
    }
    public ByteOrder getReadOrder() {
        return readOrder;
    }
    public IMessageProtocol getMessageProtocol() {
        return messageProtocol;
    }
    public int getMaxWriteBytes() {
        return maxWriteBytes;
    }
    public int getMaxReadBytes() {
        return maxReadBytes;
    }
    public long getHeartbeatFreq() {
        return heartbeatFreq;
    }
    public int getMaxHeartbeatLoseTimes() {
        return maxHeartbeatLoseTimes;
    }
    public int getConnectTimeout() {
        return connectTimeout;
    }
    public int getMaxResponseDataMb() {
        return maxResponseDataMb;
    }
    public AbsReconnection getReconnectionManager() {
        return reconnectionManager;
    }
    public SocketSSLConfig getEasySSLConfig() {
        return easySSLConfig;
    }
    public SocketFactory getSocketFactory() {
        return socketFactory;
    }
    public long getRequestTimeout() {
        return requestTimeout;
    }
    public boolean isOpenRequestTimeout() {
        return isOpenRequestTimeout;
    }
    public CallbackIDFactory getCallbackIDFactory() {
        return callbackIDFactory;
    }
    public static void setIsDebug(boolean isDebug) {
        EasySocketOptions.isDebug = isDebug;
    }
    public void setWriteOrder(ByteOrder writeOrder) {
        this.writeOrder = writeOrder;
    }
    public void setReadOrder(ByteOrder readOrder) {
        this.readOrder = readOrder;
    }
    public void setMessageProtocol(IMessageProtocol messageProtocol) {
        this.messageProtocol = messageProtocol;
    }
    public void setMaxWriteBytes(int maxWriteBytes) {
        this.maxWriteBytes = maxWriteBytes;
    }
    public void setMaxReadBytes(int maxReadBytes) {
        this.maxReadBytes = maxReadBytes;
    }
    public void setHeartbeatFreq(long heartbeatFreq) {
        this.heartbeatFreq = heartbeatFreq;
    }
    public void setMaxHeartbeatLoseTimes(int maxHeartbeatLoseTimes) {
        this.maxHeartbeatLoseTimes = maxHeartbeatLoseTimes;
    }
    public void setConnectTimeout(int connectTimeout) {
        this.connectTimeout = connectTimeout;
    }
    public void setMaxResponseDataMb(int maxResponseDataMb) {
        this.maxResponseDataMb = maxResponseDataMb;
    }
    public void setReconnectionManager(AbsReconnection reconnectionManager) {
        this.reconnectionManager = reconnectionManager;
    }
    public void setEasySSLConfig(SocketSSLConfig easySSLConfig) {
        this.easySSLConfig = easySSLConfig;
    }
    public void setSocketFactory(SocketFactory socketFactory) {
        this.socketFactory = socketFactory;
    }
    public void setCallbackIDFactory(CallbackIDFactory callbackIDFactory) {
        this.callbackIDFactory = callbackIDFactory;
    }
    public void setRequestTimeout(long requestTimeout) {
        this.requestTimeout = requestTimeout;
    }
    public void setOpenRequestTimeout(boolean openRequestTimeout) {
        isOpenRequestTimeout = openRequestTimeout;
    }
    public SocketAddress getSocketAddress() {
        return socketAddress;
    }
    public SocketAddress getBackupAddress() {
        return backupAddress;
    }
}
easysocket/src/main/java/com/easysocket/config/SocketFactory.java
New file
@@ -0,0 +1,14 @@
package com.easysocket.config;
import com.easysocket.entity.SocketAddress;
import java.net.Socket;
/**
 * Author:Alex
 * Date:2019/5/31
 * Note:socket工厂
 */
public abstract class SocketFactory {
    public abstract Socket createSocket(SocketAddress info, EasySocketOptions options) throws Exception;
}
easysocket/src/main/java/com/easysocket/config/SocketSSLConfig.java
New file
@@ -0,0 +1,81 @@
package com.easysocket.config;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
/**
 * socket的ssl配置
 */
public class SocketSSLConfig {
    /**
     * 安全协议名称(缺省为SSL)
     */
    private String mProtocol;
    /**
     * 信任证书管理器(缺省为X509)
     */
    private TrustManager[] mTrustManagers;
    /**
     * 证书秘钥管理器(缺省为null)
     */
    private KeyManager[] mKeyManagers;
    /**
     * 自定义SSLFactory(缺省为null)
     */
    private SSLSocketFactory mCustomSSLFactory;
    private SocketSSLConfig() {
    }
    public static class Builder {
        private SocketSSLConfig mConfig;
        public Builder() {
            mConfig = new SocketSSLConfig();
        }
        public Builder setProtocol(String protocol) {
            mConfig.mProtocol = protocol;
            return this;
        }
        public Builder setTrustManagers(TrustManager[] trustManagers) {
            mConfig.mTrustManagers = trustManagers;
            return this;
        }
        public Builder setKeyManagers(KeyManager[] keyManagers) {
            mConfig.mKeyManagers = keyManagers;
            return this;
        }
        public Builder setCustomSSLFactory(SSLSocketFactory customSSLFactory) {
            mConfig.mCustomSSLFactory = customSSLFactory;
            return this;
        }
        public SocketSSLConfig build() {
            return mConfig;
        }
    }
    public KeyManager[] getKeyManagers() {
        return mKeyManagers;
    }
    public String getProtocol() {
        return mProtocol;
    }
    public TrustManager[] getTrustManagers() {
        return mTrustManagers;
    }
    public SSLSocketFactory getCustomSSLFactory() {
        return mCustomSSLFactory;
    }
}
easysocket/src/main/java/com/easysocket/connection/action/IOAction.java
New file
@@ -0,0 +1,11 @@
package com.easysocket.connection.action;
/**
 * Author:Alex
 * Date:2019/6/3
 * Note:
 */
public interface IOAction {
    // 收到消息响应
    String ACTION_READ_COMPLETE = "action_read_complete";
}
easysocket/src/main/java/com/easysocket/connection/action/SocketAction.java
New file
@@ -0,0 +1,15 @@
package com.easysocket.connection.action;
/**
 * Author:Alex
 * Date:2019/6/1
 * Note:
 */
public interface SocketAction {
    // 连接成功
    String ACTION_CONN_SUCCESS="action_conn_success";
    // 连接失败
    String ACTION_CONN_FAIL="action_conn_fail";
    // 断开连接
    String ACTION_DISCONNECTION="action_disconnection";
}
easysocket/src/main/java/com/easysocket/connection/action/SocketStatus.java
New file
@@ -0,0 +1,17 @@
package com.easysocket.connection.action;
/**
 * Author:Alex
 * Date:2019/6/1
 * Note:连接状态
 */
public interface SocketStatus {
    // 已断开连接
    int SOCKET_DISCONNECTED = 0;
    // 正在连接
    int SOCKET_CONNECTING = 1;
    // 已连接
    int SOCKET_CONNECTED = 2;
    // 正在断开连接
    int SOCKET_DISCONNECTING =3;
}
easysocket/src/main/java/com/easysocket/connection/connect/SuperConnection.java
New file
@@ -0,0 +1,356 @@
package com.easysocket.connection.connect;
import android.os.Handler;
import com.easysocket.EasySocket;
import com.easysocket.callback.SuperCallBack;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.connection.action.SocketAction;
import com.easysocket.connection.action.SocketStatus;
import com.easysocket.connection.dispatcher.CallbackResponseDispatcher;
import com.easysocket.connection.dispatcher.SocketActionDispatcher;
import com.easysocket.connection.heartbeat.HeartManager;
import com.easysocket.connection.iowork.IOManager;
import com.easysocket.connection.reconnect.AbsReconnection;
import com.easysocket.entity.SocketAddress;
import com.easysocket.entity.basemsg.SuperCallbackSender;
import com.easysocket.exception.NotNullException;
import com.easysocket.interfaces.config.IConnectionSwitchListener;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.ISocketActionListener;
import com.easysocket.utils.LogUtil;
import com.easysocket.utils.Utils;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * Author:Alex
 * Date:2019/5/29
 * Note:socket连接的超类
 */
public abstract class SuperConnection implements IConnectionManager {
    /**
     * 连接状态,初始值为断开连接
     */
    protected final AtomicInteger connectionStatus = new AtomicInteger(SocketStatus.SOCKET_DISCONNECTED);
    /**
     * 连接线程
     */
    private ExecutorService connExecutor;
    /**
     * socket地址信息
     */
    protected SocketAddress socketAddress;
    /**
     * socket行为分发器
     */
    private SocketActionDispatcher actionDispatcher;
    /**
     * 重连管理器
     */
    private AbsReconnection reconnection;
    /**
     * io管理器
     */
    private IOManager ioManager;
    /**
     * 心跳管理器
     */
    private HeartManager heartManager;
    /**
     * 配置信息
     */
    protected EasySocketOptions socketOptions;
    /**
     * socket回调消息的分发器
     */
    private CallbackResponseDispatcher callbackResponseDispatcher;
    /**
     * 连接切换的监听
     */
    private IConnectionSwitchListener connectionSwitchListener;
    public SuperConnection(SocketAddress socketAddress) {
        this.socketAddress = socketAddress;
        actionDispatcher = new SocketActionDispatcher(this, socketAddress);
    }
    @Override
    public void subscribeSocketAction(ISocketActionListener iSocketActionListener) {
        actionDispatcher.subscribe(iSocketActionListener);
    }
    @Override
    public void unSubscribeSocketAction(ISocketActionListener iSocketActionListener) {
        actionDispatcher.unsubscribe(iSocketActionListener);
    }
    @Override
    public synchronized IConnectionManager setOptions(EasySocketOptions socketOptions) {
        if (socketOptions == null) return this;
        this.socketOptions = socketOptions;
        if (ioManager != null)
            ioManager.setOptions(socketOptions);
        if (heartManager != null)
            heartManager.setOptions(socketOptions);
        if (callbackResponseDispatcher != null)
            callbackResponseDispatcher.setSocketOptions(socketOptions);
        // 更改了重连器
        if (reconnection != null && !reconnection.equals(socketOptions.getReconnectionManager())) {
            reconnection.detach();
            reconnection = socketOptions.getReconnectionManager();
            reconnection.attach(this);
        }
        return this;
    }
    @Override
    public EasySocketOptions getOptions() {
        return socketOptions;
    }
    @Override
    public synchronized void connect() {
        if (connectionStatus.get() == SocketStatus.SOCKET_DISCONNECTING) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    LogUtil.d("---> socket>>connect>>正在断开连接,延时一秒執行重连");
                    connect();
                }
            }, 1000); // 延时1秒
            return;
        }
        LogUtil.d("---> socket开始连接");
        if (socketAddress.getIp() == null) {
            throw new NotNullException("请检查是否设置了IP地址");
        }
        // 正在连接
        connectionStatus.set(SocketStatus.SOCKET_CONNECTING);
        // 心跳管理器
        if (heartManager == null) {
            heartManager = new HeartManager(this, actionDispatcher);
        }
        // 重连管理器
        if (reconnection != null) {
            reconnection.detach();
        }
        reconnection = socketOptions.getReconnectionManager();
        if (reconnection != null) {
            reconnection.attach(this);
        }
        // 开启分发消息线程
        if (actionDispatcher != null) {
            actionDispatcher.startDispatchThread();
        }
        // 开启连接线程
        if (connExecutor == null || connExecutor.isShutdown()) {
            // 核心线程数为0,非核心线程数可以有Integer.MAX_VALUE个,存活时间为60秒,适合于在不断进行连接的情况下,避免重复创建和销毁线程
            connExecutor = Executors.newCachedThreadPool();
            // 执行连接任务
        }
        connExecutor.execute(connTask);
    }
    @Override
    public synchronized void disconnect(boolean isNeedReconnect) {
        // 判断当前socket的连接状态
        if (connectionStatus.get() == SocketStatus.SOCKET_DISCONNECTED) {
            return;
        }
        // 正在重连中
        if (isNeedReconnect && reconnection.isReconning()) {
            return;
        }
        // 正在断开连接
        connectionStatus.set(SocketStatus.SOCKET_DISCONNECTING);
        // 开启断开连接线程
        String info = socketAddress.getIp() + " : " + socketAddress.getPort();
        Thread disconnThread = new DisconnectThread(isNeedReconnect, "disconn thread:" + info);
        disconnThread.setDaemon(true);
        disconnThread.start();
    }
    /**
     * 断开连接线程
     */
    private class DisconnectThread extends Thread {
        boolean isNeedReconnect; // 当前连接的断开是否需要自动重连
        public DisconnectThread(boolean isNeedReconnect, String name) {
            super(name);
            this.isNeedReconnect = isNeedReconnect;
        }
        @Override
        public void run() {
            try {
                // 关闭io线程
                if (ioManager != null)
                    ioManager.closeIO();
                // 关闭回调分发器线程
                if (callbackResponseDispatcher != null)
                    callbackResponseDispatcher.shutdownThread();
                // 关闭连接线程
                if (connExecutor != null && !connExecutor.isShutdown()) {
                    connExecutor.shutdown();
                    connExecutor = null;
                }
                // 关闭连接
                closeConnection();
                actionDispatcher.dispatchAction(SocketAction.ACTION_DISCONNECTION, new Boolean(isNeedReconnect));
                if (!isNeedReconnect){
                    heartManager.stopHeartbeat();
                }
                LogUtil.d("---> 关闭socket连接");
                connectionStatus.set(SocketStatus.SOCKET_DISCONNECTED);
            } catch (IOException e) {
                // 断开连接发生异常
                e.printStackTrace();
            }
        }
    }
    // 连接任务
    private Runnable connTask = new Runnable() {
        @Override
        public void run() {
            try {
                openConnection();
            } catch (Exception e) {
                // 连接异常
                e.printStackTrace();
                LogUtil.d("---> socket连接失败");
                connectionStatus.set(SocketStatus.SOCKET_DISCONNECTED);
                // 第二个参数指需要重连
                actionDispatcher.dispatchAction(SocketAction.ACTION_CONN_FAIL, new Boolean(true));
            }
        }
    };
    /**
     * 连接成功
     */
    protected void onConnectionOpened() {
        LogUtil.d("---> socket连接成功");
        openSocketManager();
        connectionStatus.set(SocketStatus.SOCKET_CONNECTED);
        actionDispatcher.dispatchAction(SocketAction.ACTION_CONN_SUCCESS);
    }
    // 开启socket相关管理器
    private void openSocketManager() {
        if (callbackResponseDispatcher == null)
            callbackResponseDispatcher = new CallbackResponseDispatcher(this);
        if (ioManager == null) {
            ioManager = new IOManager(this, actionDispatcher);
        }
        ioManager.startIO();
        // 启动相关线程
        callbackResponseDispatcher.engineThread();
        ioManager.startIO();
    }
    // 切换了主机IP和端口
    @Override
    public synchronized void switchHost(SocketAddress socketAddress) {
        if (socketAddress != null) {
            SocketAddress oldAddress = this.socketAddress;
            this.socketAddress = socketAddress;
            if (actionDispatcher != null)
                actionDispatcher.setSocketAddress(socketAddress);
            // 切换主机
            if (connectionSwitchListener != null) {
                connectionSwitchListener.onSwitchConnectionInfo(this, oldAddress, socketAddress);
            }
        }
    }
    public void setOnConnectionSwitchListener(IConnectionSwitchListener listener) {
        connectionSwitchListener = listener;
    }
    @Override
    public boolean isConnectViable() {
        // 当前socket是否处于可连接状态
        return Utils.isNetConnected(EasySocket.getInstance().getContext()) && connectionStatus.get() == SocketStatus.SOCKET_DISCONNECTED;
    }
    @Override
    public int getConnectionStatus() {
        return connectionStatus.get();
    }
    /**
     * 打开连接
     *
     * @throws IOException
     */
    protected abstract void openConnection() throws Exception;
    /**
     * 关闭连接
     *
     * @throws IOException
     */
    protected abstract void closeConnection() throws IOException;
    /**
     * 发送bytes数据
     *
     * @param bytes
     * @return
     */
    private IConnectionManager sendBytes(byte[] bytes) {
        if (ioManager == null || connectionStatus.get() != SocketStatus.SOCKET_CONNECTED) {
            LogUtil.w("sendBytes错误-----ioManager为null或者connectionStatus状态不为已连接");
            return this;
        }
        ioManager.sendBytes(bytes);
        return this;
    }
    @Override
    public void onCallBack(SuperCallBack callBack) {
        callbackResponseDispatcher.addSocketCallback(callBack);
    }
    @Override
    public synchronized IConnectionManager upBytes(byte[] bytes) {
        sendBytes(bytes);
        return this;
    }
    @Override
    public synchronized IConnectionManager upCallbackMessage(SuperCallbackSender sender) {
        callbackResponseDispatcher.checkCallbackSender(sender);
        // 发送
        sendBytes(sender.pack());
        return this;
    }
    @Override
    public HeartManager getHeartManager() {
        return heartManager;
    }
}
easysocket/src/main/java/com/easysocket/connection/connect/TcpConnection.java
New file
@@ -0,0 +1,141 @@
package com.easysocket.connection.connect;
import com.easysocket.config.DefaultX509ProtocolTrustManager;
import com.easysocket.config.SocketSSLConfig;
import com.easysocket.connection.action.SocketStatus;
import com.easysocket.entity.SocketAddress;
import com.easysocket.utils.LogUtil;
import com.easysocket.utils.Utils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.security.SecureRandom;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
/**
 * Author:Alex
 * Date:2019/5/29
 * Note:tcp连接
 */
public class TcpConnection extends SuperConnection {
    /**
     * socket对象
     */
    private Socket socket;
    public TcpConnection(SocketAddress socketAddress) {
        super(socketAddress);
    }
    @Override
    protected void openConnection() throws Exception {
            try {
                socket = getSocket();
            } catch (Exception e) {
                e.printStackTrace();
                connectionStatus.set(SocketStatus.SOCKET_DISCONNECTED); // 设置为未连接
                throw new RuntimeException("创建socket失败");
            }
            // 进行socket连接
            socket.connect(new InetSocketAddress(socketAddress.getIp(), socketAddress.getPort()), socketOptions.getConnectTimeout());
            // 关闭Nagle算法,无论TCP数据报大小,立即发送
            socket.setTcpNoDelay(true);
            // 连接已经打开
            if (socket.isConnected() && !socket.isClosed()) {
                onConnectionOpened();
            }
    }
    @Override
    protected void closeConnection() throws IOException {
        if (socket != null)
            socket.close();
    }
    /**
     * 根据配置信息获取对应的socket
     *
     * @return
     */
    private synchronized Socket getSocket() throws Exception {
        // 自定义的socket生成工厂
        if (socketOptions.getSocketFactory() != null) {
            return socketOptions.getSocketFactory().createSocket(socketAddress, socketOptions);
        }
        // 默认操作
        SocketSSLConfig config = socketOptions.getEasySSLConfig();
        if (config == null) {
            return new Socket();
        }
        // 获取SSL配置工厂
        SSLSocketFactory factory = config.getCustomSSLFactory();
        if (factory == null) {
            String protocol = "SSL";
            if (!Utils.isStringEmpty(config.getProtocol())) {
                protocol = config.getProtocol();
            }
            TrustManager[] trustManagers = config.getTrustManagers();
            if (trustManagers == null || trustManagers.length == 0) {
                // 缺省信任所有证书
                trustManagers = new TrustManager[]{new DefaultX509ProtocolTrustManager()};
            }
            try {
                SSLContext sslContext = SSLContext.getInstance(protocol);
                sslContext.init(config.getKeyManagers(), trustManagers, new SecureRandom());
                return sslContext.getSocketFactory().createSocket();
            } catch (Exception e) {
                if (socketOptions.isDebug()) {
                    e.printStackTrace();
                }
                LogUtil.e(e.getMessage());
                return new Socket();
            }
        } else {
            try {
                return factory.createSocket();
            } catch (IOException e) {
                if (socketOptions.isDebug()) {
                    e.printStackTrace();
                }
                LogUtil.e(e.getMessage());
                return new Socket();
            }
        }
    }
    @Override
    public InputStream getInputStream() {
        if (socket != null && socket.isConnected() && !socket.isClosed()) {
            try {
                return socket.getInputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    @Override
    public OutputStream getOutStream() {
        if (socket != null && socket.isConnected() && !socket.isClosed()) {
            try {
                return socket.getOutputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}
easysocket/src/main/java/com/easysocket/connection/dispatcher/CallbackResponseDispatcher.java
New file
@@ -0,0 +1,191 @@
package com.easysocket.connection.dispatcher;
import com.easysocket.callback.SuperCallBack;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.entity.OriginReadData;
import com.easysocket.entity.SocketAddress;
import com.easysocket.entity.basemsg.SuperCallbackSender;
import com.easysocket.exception.RequestTimeOutException;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.SocketActionListener;
import com.easysocket.utils.LogUtil;
import com.easysocket.utils.Utils;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
 * Author:Alex
 * Date:2019/6/4
 * Note:回调消息分发器
 */
public class CallbackResponseDispatcher {
    /**
     * 保存发送的每个回调消息的监听实例,key为回调标识callbackId,这样回调消息有反馈的时候,就可以找到并调用
     * 对应的监听对象
     */
    private Map<String, SuperCallBack> callbacks = new HashMap<>();
    /**
     * 保存需要进行超时检测的请求,这是一个延时队列,元素超时的时候会被取出来
     */
    private DelayQueue<timeoutItem> timeoutQueue = new DelayQueue<>();
    /**
     * 超时检测的线程管理器
     */
    private ExecutorService timeoutExecutor;
    /**
     * 连接管理
     */
    IConnectionManager connectionManager;
    private EasySocketOptions socketOptions;
    public CallbackResponseDispatcher(IConnectionManager connectionManager) {
        this.connectionManager = connectionManager;
        socketOptions = connectionManager.getOptions();
        // 注册监听
        connectionManager.subscribeSocketAction(socketActionListener);
        // 开始超时检测线程
        engineThread();
    }
    /**
     * 设置socketoptions
     *
     * @param socketOptions
     */
    public void setSocketOptions(EasySocketOptions socketOptions) {
        this.socketOptions = socketOptions;
    }
    /**
     * 超时检测线程
     */
    public void engineThread() {
        try {
            if (timeoutExecutor == null || timeoutExecutor.isShutdown()) {
                timeoutExecutor = Executors.newSingleThreadExecutor();
                timeoutExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            // 只有超时的元素才会被取出,没有的话会被等待
                            timeoutItem item = timeoutQueue.take();
                            if (item != null) {
                                SuperCallBack callBack = callbacks.remove(item.callbackId);
                                if (callBack != null)
                                    callBack.onError(new RequestTimeOutException("request timeout"));
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        // 继续循环
                        if (timeoutExecutor != null && !timeoutExecutor.isShutdown()) {
                            run();
                        }
                    }
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 关闭线程
     */
    public void shutdownThread() {
        if (timeoutExecutor != null && !timeoutExecutor.isShutdown()) {
            // shutdown和shutdownNow的主要区别是前者中断未执行的线程,后者中断所有线程
            timeoutExecutor.shutdownNow();
            timeoutExecutor = null;
        }
    }
    /**
     * socket行为监听,重写反馈消息的回调方法
     */
    private SocketActionListener socketActionListener = new SocketActionListener() {
        @Override
        public void onSocketResponse(SocketAddress socketAddress, OriginReadData originReadData) {
            if (callbacks.size() == 0) return;
            if (socketOptions.getCallbackIDFactory() == null) return;
            // 获取回调ID
            String callbackID = socketOptions.getCallbackIDFactory().getCallbackID(originReadData);
            if (callbackID != null) {
                // 获取callbackID对应的callback
                SuperCallBack callBack = callbacks.get(callbackID);
                if (callBack != null) {
                    // 回调
                    callBack.onSuccess(originReadData);
                    callbacks.remove(callbackID); // 移除完成任务的callback
                    LogUtil.d("移除的callbackId-->" + callbackID);
                }
            }
        }
    };
    /**
     * 每发一条回调消息都要在这里添加监听对象
     *
     * @param superCallBack
     */
    public void addSocketCallback(SuperCallBack superCallBack) {
        callbacks.put(superCallBack.getCallbackId(), superCallBack);
        // 放入延时队列
        long delayTime = socketOptions == null ?
                EasySocketOptions.getDefaultOptions().getRequestTimeout() : socketOptions.getRequestTimeout();
        timeoutQueue.add(new timeoutItem(superCallBack.getCallbackId(), delayTime, TimeUnit.MILLISECONDS));
    }
    /**
     * 延时队列的item
     */
    class timeoutItem implements Delayed {
        String callbackId; // 当前callback的callbackId
        long executeTime; // 触发时间
        public timeoutItem(String callbackId, long delayTime, TimeUnit timeUnit) {
            this.callbackId = callbackId;
            this.executeTime = System.currentTimeMillis() + (delayTime > 0 ? timeUnit.toMillis(delayTime) : 0);
        }
        @Override
        public long getDelay(TimeUnit unit) {
            return executeTime - System.currentTimeMillis();
        }
        @Override
        public int compareTo(Delayed o) {
            return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
        }
    }
    /**
     * 同一个消息发送多次,callbackId是不能一样的,所以这里要先check一下,否则服务端反馈的时候,客户端接收就会乱套
     *
     * @param callbackSender
     * @return
     */
    public void checkCallbackSender(SuperCallbackSender callbackSender) {
        Utils.checkNotNull(socketOptions.getCallbackIDFactory(), "要想实现EasySocket的回调功能,CallbackIdFactory不能为null," +
                "请实现一个CallbackIdFactory并在初始化的时候通过EasySocketOptions的setCallbackIdFactory进行配置");
        String callbackId = callbackSender.getCallbackId();
        // 同一个消息发送两次以上,callbackId是不能一样的,否则服务端反馈的时候,客户端接收就会乱套
        if (callbacks.containsKey(callbackId)) {
            callbackSender.generateCallbackId();
        }
    }
}
easysocket/src/main/java/com/easysocket/connection/dispatcher/MainThreadExecutor.java
New file
@@ -0,0 +1,21 @@
package com.easysocket.connection.dispatcher;
import android.os.Handler;
import android.os.Looper;
import java.util.concurrent.Executor;
/**
 * Author:Mapogo
 * Date:2020/4/8
 * Note:切到主线程
 */
public class MainThreadExecutor implements Executor {
    private final Handler handler = new Handler(Looper.getMainLooper());
    @Override
    public void execute(Runnable r) {
        handler.post(r);
    }
}
easysocket/src/main/java/com/easysocket/connection/dispatcher/SocketActionDispatcher.java
New file
@@ -0,0 +1,221 @@
package com.easysocket.connection.dispatcher;
import com.easysocket.EasySocket;
import com.easysocket.entity.OriginReadData;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.ISocketActionDispatch;
import com.easysocket.interfaces.conn.ISocketActionListener;
import com.easysocket.utils.Utils;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import static com.easysocket.connection.action.IOAction.ACTION_READ_COMPLETE;
import static com.easysocket.connection.action.SocketAction.ACTION_CONN_FAIL;
import static com.easysocket.connection.action.SocketAction.ACTION_CONN_SUCCESS;
import static com.easysocket.connection.action.SocketAction.ACTION_DISCONNECTION;
/**
 * Author:Alex
 * Date:2019/6/1
 * Note:socket行为分发器
 */
public class SocketActionDispatcher implements ISocketActionDispatch {
    /**
     * 连接地址
     */
    private SocketAddress socketAddress;
    /**
     * 连接器
     */
    private IConnectionManager connectionManager;
    /**
     * 回调监听集合
     */
    private List<ISocketActionListener> actionListeners = new ArrayList<>();
    /**
     * 处理socket行为的线程
     */
    private Thread actionThread;
    /**
     * 是否停止分发
     */
    private boolean isStop;
    /**
     * 事件消费队列
     */
    private final LinkedBlockingQueue<ActionBean> socketActions = new LinkedBlockingQueue();
    /**
     * 切换到UI线程
     */
    private MainThreadExecutor mainThreadExecutor = new MainThreadExecutor();
    public SocketActionDispatcher(IConnectionManager connectionManager, SocketAddress socketAddress) {
        this.socketAddress = socketAddress;
        this.connectionManager = connectionManager;
    }
    public void setSocketAddress(SocketAddress info) {
        socketAddress = info;
    }
    @Override
    public void dispatchAction(String action) {
        dispatchAction(action, null);
    }
    @Override
    public void dispatchAction(String action, Serializable serializable) {
        // 将接收到的socket行为封装入列
        ActionBean actionBean = new ActionBean(action, serializable, this);
        socketActions.offer(actionBean);
    }
    @Override
    public void subscribe(ISocketActionListener iSocketActionListener) {
        if (iSocketActionListener != null && !actionListeners.contains(iSocketActionListener)) {
            actionListeners.add(iSocketActionListener);
        }
    }
    @Override
    public void unsubscribe(ISocketActionListener iSocketActionListener) {
        actionListeners.remove(iSocketActionListener);
    }
    /**
     * 分发线程
     */
    private class DispatchThread extends Thread {
        public DispatchThread() {
            super("dispatch thread");
        }
        @Override
        public void run() {
            // 循环处理socket的行为信息
            while (!isStop) {
                try {
                    ActionBean actionBean = socketActions.take();
                    if (actionBean != null && actionBean.mDispatcher != null) {
                        SocketActionDispatcher actionDispatcher = actionBean.mDispatcher;
                        List<ISocketActionListener> copyListeners = new ArrayList<>(actionDispatcher.actionListeners);
                        Iterator<ISocketActionListener> listeners = copyListeners.iterator();
                        // 通知所有监听者
                        while (listeners.hasNext()) {
                            ISocketActionListener listener = listeners.next();
                            actionDispatcher.dispatchActionToListener(actionBean.mAction, actionBean.arg, listener);
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * socket行为的封装
     */
    protected static class ActionBean {
        public ActionBean(String action, Serializable arg, SocketActionDispatcher dispatcher) {
            mAction = action;
            this.arg = arg;
            mDispatcher = dispatcher;
        }
        String mAction = "";
        Serializable arg;
        SocketActionDispatcher mDispatcher;
    }
    /**
     * 分发行为给监听者
     *
     * @param action
     * @param content
     * @param actionListener
     */
    private void dispatchActionToListener(String action, final Serializable content, final ISocketActionListener actionListener) {
        switch (action) {
            case ACTION_CONN_SUCCESS: // 连接成功
                mainThreadExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        actionListener.onSocketConnSuccess(socketAddress);
                    }
                });
                break;
            case ACTION_CONN_FAIL: // 连接失败
                mainThreadExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        actionListener.onSocketConnFail(socketAddress, ((Boolean) content).booleanValue());
                    }
                });
                break;
            case ACTION_DISCONNECTION: // 连接断开
                mainThreadExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        actionListener.onSocketDisconnect(socketAddress, ((Boolean) content).booleanValue());
                        // 不需要重连,则释放资源
                        if (!(Boolean) content) {
                            stopDispatchThread();
                        }
                    }
                });
                break;
            case ACTION_READ_COMPLETE: // 读取数据完成
                mainThreadExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        // response有三种形式
                        actionListener.onSocketResponse(socketAddress, (OriginReadData) content);
                        byte[] data = Utils.concatBytes(((OriginReadData) content).getHeaderData(), ((OriginReadData) content).getBodyBytes());
                        actionListener.onSocketResponse(socketAddress, new String(data, Charset.forName(EasySocket.getInstance().getDefOptions().getCharsetName())));
                        actionListener.onSocketResponse(socketAddress, data);
                    }
                });
                break;
        }
    }
    // 开始分发线程
    @Override
    public void startDispatchThread() {
        isStop = false;
        if (actionThread == null) {
            actionThread = new DispatchThread();
            actionThread.start();
        }
    }
    @Override
    public void stopDispatchThread() {
        if (actionThread != null && actionThread.isAlive() && !actionThread.isInterrupted()) {
            socketActions.clear();
            //actionListeners.clear();
            isStop = true;
            actionThread.interrupt();
            actionThread = null;
        }
    }
}
easysocket/src/main/java/com/easysocket/connection/heartbeat/HeartManager.java
New file
@@ -0,0 +1,181 @@
package com.easysocket.connection.heartbeat;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.entity.OriginReadData;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.config.IOptions;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.IHeartManager;
import com.easysocket.interfaces.conn.ISocketActionDispatch;
import com.easysocket.interfaces.conn.SocketActionListener;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * Author:Alex
 * Date:2019/12/8
 * Note:心跳包检测管理器
 */
public class HeartManager extends SocketActionListener implements IOptions, IHeartManager {
    /**
     * 连接器
     */
    private IConnectionManager connectionManager;
    /**
     * 连接参数
     */
    private EasySocketOptions socketOptions;
    /**
     * 客户端心跳包
     */
    private byte[] clientHeart;
    /**
     * 心跳包发送线程
     */
    private ScheduledExecutorService heartExecutor;
    /**
     * 记录心跳的失联次数
     */
    private AtomicInteger loseTimes = new AtomicInteger(-1);
    /**
     * 心跳频率
     */
    private long freq;
    /**
     * 是否激活了心跳
     */
    private boolean isActivate;
    /**
     * 心跳包接收监听
     */
    private HeartbeatListener heartbeatListener;
    public HeartManager(IConnectionManager iConnectionManager, ISocketActionDispatch actionDispatch) {
        this.connectionManager = iConnectionManager;
        socketOptions = iConnectionManager.getOptions();
        actionDispatch.subscribe(this); // 注册监听
    }
    /**
     * 心跳发送任务
     */
    private final Runnable beatTask = new Runnable() {
        @Override
        public void run() {
            // 心跳丢失次数判断,心跳包丢失了一定的次数则会进行socket的断开重连
            if (socketOptions.getMaxHeartbeatLoseTimes() != -1
                    && loseTimes.incrementAndGet() >= socketOptions.getMaxHeartbeatLoseTimes()) {
                // 断开重连
                connectionManager.disconnect(true);
                resetLoseTimes();
            } else { // 发送心跳包
                connectionManager.upBytes(clientHeart);
            }
        }
    };
    @Override
    public void startHeartbeat(byte[] clientHeart, HeartbeatListener listener) {
        this.clientHeart = clientHeart;
        this.heartbeatListener = listener;
        isActivate = true;
        openThread();
    }
    // 启动心跳线程
    private void openThread() {
        freq = socketOptions.getHeartbeatFreq(); // 心跳频率
        //  启动线程发送心跳
        if (heartExecutor == null || heartExecutor.isShutdown()) {
            heartExecutor = Executors.newSingleThreadScheduledExecutor();
            heartExecutor.scheduleWithFixedDelay(beatTask, 0, freq, TimeUnit.MILLISECONDS);
        }
    }
    /**
     * 停止心跳发送
     */
    @Override
    public void stopHeartbeat() {
        isActivate = false;
        closeThread();
    }
    // 停止心跳线程
    private void closeThread() {
        if (heartExecutor != null && !heartExecutor.isShutdown()) {
            heartExecutor.shutdownNow();
            heartExecutor = null;
            resetLoseTimes(); // 重置
        }
    }
    @Override
    public void onReceiveHeartBeat() {
        resetLoseTimes();
    }
    private void resetLoseTimes() {
        loseTimes.set(-1);
    }
    @Override
    public void onSocketConnSuccess(SocketAddress socketAddress) {
        if (isActivate) {
            openThread();
        }
    }
    @Override
    public void onSocketConnFail(SocketAddress socketAddress, boolean isNeedReconnect) {
        // 如果不需要重连,则停止心跳频率线程
        if (!isNeedReconnect) {
            closeThread();
        }
    }
    @Override
    public void onSocketDisconnect(SocketAddress socketAddress, boolean isNeedReconnect) {
        // 如果不需要重连,则停止心跳检测
        if (!isNeedReconnect) {
            closeThread();
        }
    }
    @Override
    public void onSocketResponse(SocketAddress socketAddress, OriginReadData originReadData) {
        if (heartbeatListener != null && heartbeatListener.isServerHeartbeat(originReadData)) {
            // 收到服务器心跳
            onReceiveHeartBeat();
        }
    }
    @Override
    public Object setOptions(EasySocketOptions socketOptions) {
        this.socketOptions = socketOptions;
        freq = socketOptions.getHeartbeatFreq();
        freq = freq < 1000 ? 1000 : freq; // 不能小于一秒
        return this;
    }
    @Override
    public EasySocketOptions getOptions() {
        return socketOptions;
    }
    public interface HeartbeatListener {
        // 是否为服务器心跳
        boolean isServerHeartbeat(OriginReadData orginReadData);
    }
}
easysocket/src/main/java/com/easysocket/connection/iowork/EasyReader.java
New file
@@ -0,0 +1,337 @@
package com.easysocket.connection.iowork;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.connection.action.IOAction;
import com.easysocket.connection.action.SocketStatus;
import com.easysocket.entity.OriginReadData;
import com.easysocket.exception.ReadRecoverableExeption;
import com.easysocket.exception.ReadUnrecoverableException;
import com.easysocket.interfaces.config.IMessageProtocol;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.ISocketActionDispatch;
import com.easysocket.interfaces.io.IReader;
import com.easysocket.utils.HexUtil;
import com.easysocket.utils.LogUtil;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
/**
 * Author:Alex
 * Date:2019/6/1
 * Note:
 */
public class EasyReader implements IReader<EasySocketOptions> {
    /**
     * 输入流
     */
    private InputStream inputStream;
    /**
     * 读取原始数据的缓存空间
     */
    private ByteBuffer originBuf;
    /**
     * socket行为分发器
     */
    private ISocketActionDispatch actionDispatch;
    /**
     * 连接器
     */
    private IConnectionManager connectionManager;
    /**
     * 连接参数
     */
    private EasySocketOptions socketOptions;
    /**
     * 读数据时,余留数据的缓存
     */
    private ByteBuffer remainingBuf;
    /**
     * 读数据线程
     */
    private Thread readerThread;
    /**
     * 是否停止线程
     */
    private boolean stopThread;
    public EasyReader(IConnectionManager connectionManager, ISocketActionDispatch actionDispatch) {
        this.actionDispatch = actionDispatch;
        this.connectionManager = connectionManager;
        socketOptions = connectionManager.getOptions();
    }
    @Override
    public void read() throws IOException, ReadRecoverableExeption, ReadUnrecoverableException {
        OriginReadData originalData = new OriginReadData();
        IMessageProtocol messageProtocol = socketOptions.getMessageProtocol();
        // 消息协议为null,则直接读原始消息,不建议这样使用,因为会发生黏包、分包的问题
        if (messageProtocol == null) {
            readOriginDataFromSteam(originalData);
            return;
        }
        // 定义了消息协议
        int headerLength = messageProtocol.getHeaderLength(); // 包头长度
        ByteBuffer headBuf = ByteBuffer.allocate(headerLength); // 包头数据的buffer
        headBuf.order(socketOptions.getReadOrder());
        /*1、读 header=====>>>*/
        if (remainingBuf != null) { // 有余留
            // flip方法:一般从Buffer读数据前调用,将limit设置为当前position,将position设置为0,在读数据时,limit代表可读数据的有效长度
            remainingBuf.flip();
            // 读余留数据的长度
            int length = Math.min(remainingBuf.remaining(), headerLength);
            // 读入余留数据
            headBuf.put(remainingBuf.array(), 0, length);
            if (length < headerLength) { // 余留数据小于一个header
                // there are no data left
                remainingBuf = null;
                // 从stream中读剩下的header数据
                readHeaderFromSteam(headBuf, headerLength - length);
            } else {
                // 移动开始读数据的指针
                remainingBuf.position(headerLength);
            }
        } else { // 无余留
            // 从stream读取一个完整的 header
            readHeaderFromSteam(headBuf, headBuf.capacity());
        }
        // 保存header
        originalData.setHeaderData(headBuf.array());
        /*2、读 body=====>>>*/
        int bodyLength = messageProtocol.getBodyLength(originalData.getHeaderData(), socketOptions.getReadOrder());
        if (bodyLength > 0) {
            if (bodyLength > socketOptions.getMaxResponseDataMb() * 1024 * 1024) {
                throw new ReadUnrecoverableException("服务器返回的单次数据超过了规定的最大值,可能你的Socket消息协议不对,一般消息格式" +
                        "为:Header+Body,其中Header保存消息长度和类型等,Body保存消息内容,请规范好你的协议");
            }
            // 分配空间
            ByteBuffer bodyBuf = ByteBuffer.allocate(bodyLength);
            bodyBuf.order(socketOptions.getReadOrder());
            // 有余留
            if (remainingBuf != null) {
                int bodyStartPosition = remainingBuf.position();
                int length = Math.min(remainingBuf.remaining(), bodyLength);
                // 读length大小的余留数据
                bodyBuf.put(remainingBuf.array(), bodyStartPosition, length);
                // 移动position位置
                remainingBuf.position(bodyStartPosition + length);
                // 读的余留数据刚好等于一个body
                if (length == bodyLength) {
                    if (remainingBuf.remaining() > 0) { // 余留数据未读完
                        ByteBuffer temp = ByteBuffer.allocate(remainingBuf.remaining());
                        temp.order(socketOptions.getReadOrder());
                        temp.put(remainingBuf.array(), remainingBuf.position(), remainingBuf.remaining());
                        remainingBuf = temp;
                    } else { // there are no data left
                        remainingBuf = null;
                    }
                    // 保存body
                    originalData.setBodyData(bodyBuf.array());
                    LogUtil.d("Socket收到数据-->" +HexUtil.bytesToHex(originalData.getBodyBytes()) );
                    // 分发数据
                    actionDispatch.dispatchAction(IOAction.ACTION_READ_COMPLETE, originalData);
                    /*return读取结束*/
                    return;
                } else { // there are no data left in buffer and some data pieces in channel
                    remainingBuf = null;
                }
            }
            // 无余留,则从stream中读
            readBodyFromStream(bodyBuf);
            // 保存body到originalData
            originalData.setBodyData(bodyBuf.array());
        } else if (bodyLength == 0) { // 没有body数据
            originalData.setBodyData(new byte[0]);
            if (remainingBuf != null) {
                // the body is empty so header remaining buf need set null
                if (remainingBuf.hasRemaining()) {
                    ByteBuffer temp = ByteBuffer.allocate(remainingBuf.remaining());
                    temp.order(socketOptions.getReadOrder());
                    temp.put(remainingBuf.array(), remainingBuf.position(), remainingBuf.remaining());
                    remainingBuf = temp;
                } else {
                    remainingBuf = null;
                }
            }
        } else if (bodyLength < 0) {
            throw new ReadUnrecoverableException("数据body的长度不能小于0");
        }
        LogUtil.d("Socket收到数据-->" + HexUtil.bytesToHex(originalData.getBodyBytes()));
        // 分发
        actionDispatch.dispatchAction(IOAction.ACTION_READ_COMPLETE, originalData);
    }
    /**
     * 读数据任务
     */
    private Runnable readerTask = new Runnable() {
        @Override
        public void run() {
            try {
                while (!stopThread) {
                    read();
                }
            } catch (ReadUnrecoverableException unrecoverableException) {
                // 读异常
                unrecoverableException.printStackTrace();
                // 停止线程
                stopThread = true;
                release();
            } catch (ReadRecoverableExeption readRecoverableExeption) {
                readRecoverableExeption.printStackTrace();
                // 重连
                LogUtil.d("--->重连 ReadRecoverableExeption");
                connectionManager.disconnect(true);
            } catch (IOException e) {
                e.printStackTrace();
                // 重连
                LogUtil.d("--->重连 IOException");
                if (connectionManager.getConnectionStatus() != SocketStatus.SOCKET_DISCONNECTING) {
                    connectionManager.disconnect(true);
                }
            }
        }
    };
    private void readHeaderFromSteam(ByteBuffer headBuf, int readLength) throws ReadRecoverableExeption, IOException {
        for (int i = 0; i < readLength; i++) {
            byte[] bytes = new byte[1];
            // 从输入流中读数据,无数据时会阻塞
            int value = inputStream.read(bytes);
            // -1代表读到了文件的末尾,一般是因为服务器断开了连接
            if (value == -1) {
                throw new ReadRecoverableExeption("读数据失败,可能是因为socket跟服务器断开了连接");
            }
            headBuf.put(bytes);
        }
    }
    private void readOriginDataFromSteam(OriginReadData readData) throws ReadRecoverableExeption, IOException {
        // 用 全局originBuf避免重复创建字节数组
        int len = inputStream.read(originBuf.array());
        // no more data
        if (len == -1) {
            throw new ReadRecoverableExeption("读数据失败,可能因为socket跟服务器断开了连接");
        }
        // bytes复制
        byte[] data = new byte[len];
        originBuf.get(data, 0, len);
        readData.setBodyData(data);
        LogUtil.d("Socket收到数据-->" + HexUtil.bytesToHex(readData.getBodyBytes()));
        // 分发数据
        actionDispatch.dispatchAction(IOAction.ACTION_READ_COMPLETE, readData);
        // 相当于把指针重新指向positon=0
        originBuf.clear();
    }
    private void readBodyFromStream(ByteBuffer byteBuffer) throws ReadRecoverableExeption, IOException {
        // while循环直到byteBuffer装满数据
        while (byteBuffer.hasRemaining()) {
            byte[] bufArray = new byte[socketOptions.getMaxReadBytes()]; // 从服务器单次读取的最大值
            int len = inputStream.read(bufArray);
            if (len == -1) { // no more data
                throw new ReadRecoverableExeption("读数据失败,可能是因为socket跟服务器断开了连接");
            }
            int remaining = byteBuffer.remaining();
            if (len > remaining) { // 从stream读的数据超过byteBuffer的剩余空间
                byteBuffer.put(bufArray, 0, remaining);
                // 将多余的数据保存到remainingBuf中缓存,等下一次读取
                remainingBuf = ByteBuffer.allocate(len - remaining);
                remainingBuf.order(socketOptions.getReadOrder());
                remainingBuf.put(bufArray, remaining, len - remaining);
            } else { // 从stream读的数据小于或等于byteBuffer的剩余空间
                byteBuffer.put(bufArray, 0, len);
            }
        }
    }
    @Override
    public void openReader() {
        init();
        if (readerThread == null || !readerThread.isAlive()) {
            readerThread = new Thread(readerTask, "reader thread");
            stopThread = false;
            readerThread.start();
        }
    }
    @Override
    public void closeReader() {
        try {
            // 关闭线程释放资源
            shutDownThread();
            release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    // 释放资源
    private void release() {
        if (originBuf != null) {
            originBuf = null;
        }
        if (remainingBuf != null) {
            remainingBuf = null;
        }
        if (readerThread != null && !readerThread.isAlive()) {
            readerThread = null;
        }
        try {
            if (inputStream != null)
                inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            inputStream = null;
        }
    }
    // 初始化
    private void init() {
        inputStream = connectionManager.getInputStream();
        // 没有定义消息协议
        if (socketOptions.getMessageProtocol() == null) {
            originBuf = ByteBuffer.allocate(1024 * 4);
        }
    }
    @Override
    public void setOption(EasySocketOptions socketOptions) {
        this.socketOptions = socketOptions;
    }
    // 关闭读数据线程
    private void shutDownThread() throws InterruptedException {
        if (readerThread != null && readerThread.isAlive() && !readerThread.isInterrupted()) {
            try {
                stopThread = true;
                readerThread.interrupt();
                readerThread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
easysocket/src/main/java/com/easysocket/connection/iowork/EasyWriter.java
New file
@@ -0,0 +1,151 @@
package com.easysocket.connection.iowork;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.ISocketActionDispatch;
import com.easysocket.interfaces.io.IWriter;
import com.easysocket.utils.HexUtil;
import com.easysocket.utils.LogUtil;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.concurrent.LinkedBlockingDeque;
/**
 * Author:Alex
 * Date:2019/6/1
 * Note:
 */
public class EasyWriter implements IWriter<EasySocketOptions> {
    /**
     * 输出流
     */
    private OutputStream outputStream;
    /**
     * 连接管理器
     */
    private IConnectionManager connectionManager;
    /**
     * socket参数
     */
    private EasySocketOptions socketOptions;
    /**
     * 行为分发
     */
    private ISocketActionDispatch actionDispatch;
    /**
     * 写数据线程
     */
    private Thread writerThread;
    /**
     * 是否停止写数据
     */
    private boolean isStop;
    /**
     * 待写入数据
     */
    private LinkedBlockingDeque<byte[]> packetsToSend = new LinkedBlockingDeque<>();
    public EasyWriter(IConnectionManager connectionManager, ISocketActionDispatch actionDispatch) {
        this.connectionManager = connectionManager;
        socketOptions = connectionManager.getOptions();
        this.actionDispatch = actionDispatch;
    }
    @Override
    public void openWriter() {
        outputStream = connectionManager.getOutStream();
        if (writerThread == null) {
            isStop = false;
            writerThread = new Thread(writerTask, "writer thread");
            writerThread.start();
        }
    }
    @Override
    public void setOption(EasySocketOptions socketOptions) {
        this.socketOptions = socketOptions;
    }
    /**
     * 写任务
     */
    private Runnable writerTask = new Runnable() {
        @Override
        public void run() {
            // 循环写数据
            while (!isStop) {
                try {
                    byte[] sender = packetsToSend.take();
                    write(sender);
                } catch (InterruptedException | IOException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    @Override
    public void write(byte[] sendBytes) throws IOException {
        if (sendBytes != null) {
            LogUtil.d("EasyWriter--Socket发送数据String-->" + HexUtil.bytesToHex(sendBytes));
            LogUtil.d("EasyWriter--Socket发送数据byte[]-->" + Arrays.toString(sendBytes));
            int packageSize = socketOptions.getMaxWriteBytes(); // 每次可以发送的最大数据
            int remainingCount = sendBytes.length;
            ByteBuffer writeBuf = ByteBuffer.allocate(packageSize);
            writeBuf.order(socketOptions.getReadOrder());
            int index = 0;
            // 如果发送的数据大于单次可发送的最大数据,则分多次发送
            while (remainingCount > 0) {
                int realWriteLength = Math.min(packageSize, remainingCount);
                writeBuf.clear(); // 清空缓存
                writeBuf.rewind(); // 将position位置移到0
                writeBuf.put(sendBytes, index, realWriteLength);
                writeBuf.flip();
                byte[] writeArr = new byte[realWriteLength];
                writeBuf.get(writeArr);
                outputStream.write(writeArr);
                outputStream.flush(); // 强制写入缓存中残留数据
                index += realWriteLength;
                remainingCount -= realWriteLength;
            }
        }
    }
    @Override
    public void offer(byte[] sender) {
        if (!isStop)
            packetsToSend.offer(sender);
    }
    @Override
    public void closeWriter() {
        try {
            if (outputStream != null)
                outputStream.close();
            shutDownThread();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            outputStream = null;
        }
    }
    private void shutDownThread() throws InterruptedException {
        if (writerThread != null && writerThread.isAlive() && !writerThread.isInterrupted()) {
            try {
                isStop = true;
                writerThread.interrupt();
                writerThread.join();
                writerThread = null;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
easysocket/src/main/java/com/easysocket/connection/iowork/IOManager.java
New file
@@ -0,0 +1,98 @@
package com.easysocket.connection.iowork;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.interfaces.config.IOptions;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.ISocketActionDispatch;
import com.easysocket.interfaces.io.IIOManager;
import com.easysocket.interfaces.io.IReader;
import com.easysocket.interfaces.io.IWriter;
/**
 * Author:Alex
 * Date:2019/5/28
 * Note:
 */
public class IOManager implements IIOManager, IOptions {
    /**
     * socket行为回调
     */
    private ISocketActionDispatch actionDispatch;
    /**
     * 连接管理
     */
    private IConnectionManager connectionManager;
    /**
     * 写
     */
    private IWriter writer;
    /**
     * 读
     */
    private IReader reader;
    public IOManager(IConnectionManager connectionManager,
                     ISocketActionDispatch connActionDispatch) {
        this.connectionManager = connectionManager;
        this.actionDispatch = connActionDispatch;
        initIO();
    }
    //  初始化io
    private void initIO() {
        //makesureHeaderProtocolNotEmpty();
        reader = new EasyReader(connectionManager, actionDispatch); //  读
        writer = new EasyWriter(connectionManager, actionDispatch); //  写
    }
    @Override
    public void sendBytes(byte[] bytes) {
        if (writer != null)
            writer.offer(bytes);
    }
    @Override
    public void startIO() {
        if (writer != null)
            writer.openWriter();
        if (reader != null)
            reader.openReader();
    }
    @Override
    public void closeIO() {
        if (writer != null)
            writer.closeWriter();
        if (reader != null)
            reader.closeReader();
    }
    @Override
    public Object setOptions(EasySocketOptions socketOptions) {
        //makesureHeaderProtocolNotEmpty();
        if (writer != null)
            writer.setOption(socketOptions);
        if (reader != null)
            reader.setOption(socketOptions);
        return this;
    }
    @Override
    public EasySocketOptions getOptions() {
        return connectionManager.getOptions();
    }
    /**
     * 确保包结构协议不为空
     */
//    private void makesureHeaderProtocolNotEmpty() {
//        IMessageProtocol protocol = connectionManager.getOptions().getMessageProtocol();
//        if (protocol == null) {
//            throw new NoNullException("The reader protocol can not be Null.");
//        }
//
//        if (protocol.getHeaderLength() == 0) {
//            throw new NoNullException("The header length can not be zero.");
//        }
//    }
}
easysocket/src/main/java/com/easysocket/connection/reconnect/AbsReconnection.java
New file
@@ -0,0 +1,52 @@
package com.easysocket.connection.reconnect;
import com.easysocket.entity.OriginReadData;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.IReconnListener;
import com.easysocket.interfaces.conn.SocketActionListener;
/**
 * Author:Alex
 * Date:2019/5/31
 * Note:抽象重连器
 */
public abstract class AbsReconnection extends SocketActionListener implements IReconnListener {
    /**
     * 连接管理器
     */
    protected IConnectionManager connectionManager;
    /**
     * socket连接管理器是否已销毁
     */
    protected boolean isDetach;
    @Override
    public synchronized void attach(IConnectionManager iConnectionManager) {
        if (!isDetach) {
            detach();
        }
        isDetach = false;
        connectionManager = iConnectionManager;
        connectionManager.subscribeSocketAction(this); // 监听socket行为
    }
    @Override
    public synchronized void detach() {
        isDetach = true;
        if (connectionManager != null)
            connectionManager.unSubscribeSocketAction(this);
    }
    @Override
    public void onSocketResponse(SocketAddress socketAddress, OriginReadData originReadData) {
        // donothing
    }
    /**
     * 是否正在重连
     * @return
     */
    public abstract boolean isReconning();
}
easysocket/src/main/java/com/easysocket/connection/reconnect/DefaultReConnection.java
New file
@@ -0,0 +1,148 @@
package com.easysocket.connection.reconnect;
import android.os.Handler;
import android.os.HandlerThread;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.utils.LogUtil;
/**
 * Author:Alex
 * Date:2019/5/28
 * Note:默认重连器
 */
public class DefaultReConnection extends AbsReconnection {
    /**
     * 最大连接失败次数,超过可以切换到备用的服务器地址
     */
    private static final int MAX_CONNECTION_FAILED_TIMES = 10;
    /**
     * 连接失败的次数
     */
    private int connectionFailedTimes = 0;
    /**
     * 重连间隔不能小于10秒,为了避免全部客户端socket在同一时间连接服务端,间隔时间需要上下浮动50%
     */
    private long reconnectTimeDelay = 10 * 1000;
    /**
     * 重连线程
     */
    private HandlerThread handlerThread;
    /**
     * 实现延时任务的 handler
     */
    private Handler handler;
    public DefaultReConnection() {
    }
    @Override
    public synchronized void attach(IConnectionManager iConnectionManager) {
        super.attach(iConnectionManager);
        if (reconnectTimeDelay < connectionManager.getOptions().getConnectTimeout()) {
            reconnectTimeDelay = connectionManager.getOptions().getConnectTimeout();
        }
    }
    /**
     * 重连任务
     */
    private final Runnable RcConnTask = new Runnable() {
        @Override
        public void run() {
            LogUtil.d("---> 执行重连");
            if (isDetach) {
                shutDown();
                return;
            }
            // 是否可连接的
            if (!connectionManager.isConnectViable()) {
                LogUtil.d("当前条件不允许连接");
                // 尝试再次重连
                handler.postDelayed(RcConnTask, (long) (reconnectTimeDelay * (Math.random() + 0.5)));
                return;
            }
            // 重连
            connectionManager.connect();
        }
    };
    /**
     * 进行重连
     */
    private void reconnect() {
        if (handlerThread == null) {
            handlerThread = new HandlerThread("re_conn");
            handlerThread.start();
            handler = new Handler(handlerThread.getLooper());
        }
        LogUtil.d("重连间隔时间-->" + reconnectTimeDelay * (Math.random() + 0.5));
        handler.postDelayed(RcConnTask, (long) (reconnectTimeDelay * (Math.random() + 0.5)));
    }
    // 关闭重连线程
    private void shutDown() {
        if (handlerThread != null && handlerThread.isAlive()) {
            handlerThread.quit();
            handlerThread = null;
            handler = null;
        }
    }
    @Override
    public boolean equals(Object o) {
        // getClass返回Class类型的对象,比较它们的类型对象是否==,其实是比较它们是否为同一个Class创建的对象
        if (o == null || getClass() != o.getClass()) return false;
        return true;
    }
    @Override
    public void onSocketConnSuccess(SocketAddress socketAddress) {
        // 连接成功关闭重连线程
        shutDown();
    }
    @Override
    public void onSocketConnFail(SocketAddress socketAddress, boolean isNeedReconnect) {
        // 不需要重连,则关闭重连线程
        if (!isNeedReconnect) {
            shutDown();
            return;
        }
        connectionFailedTimes++;
        // 如果大于最大连接次数并且有备用host,则轮流切换两个host
        if (connectionFailedTimes > MAX_CONNECTION_FAILED_TIMES && socketAddress.getBackupAddress() != null) {
            connectionFailedTimes = 0; // 归零
            SocketAddress backupAddress = socketAddress.getBackupAddress();
            SocketAddress nowAddress = new SocketAddress(socketAddress.getIp(), socketAddress.getPort());
            backupAddress.setBackupAddress(nowAddress);
            if (connectionManager.isConnectViable()) {
                connectionManager.switchHost(backupAddress);
                // 切换主机地址,重新连接
                reconnect();
            }
        } else {
            reconnect();
        }
    }
    @Override
    public void onSocketDisconnect(SocketAddress socketAddress, boolean isNeedReconnect) {
        // 是否需要重连
        if (!isNeedReconnect) {
            shutDown();
            return;
        }
        reconnect();
    }
    @Override
    public boolean isReconning() {
        return handlerThread != null && handlerThread.isAlive();
    }
}
easysocket/src/main/java/com/easysocket/entity/OriginReadData.java
New file
@@ -0,0 +1,58 @@
package com.easysocket.entity;
import com.easysocket.EasySocket;
import com.easysocket.utils.Utils;
import java.io.Serializable;
import java.nio.charset.Charset;
/**
 * Author:Alex
 * Date:2019/6/1
 * Note:读到的数据
 */
public class OriginReadData implements Serializable {
    /**
     * 包头数据
     */
    private byte[] headerData;
    /**
     * 包体数据
     */
    private byte[] bodyData;
    public byte[] getHeaderData() {
        return headerData;
    }
    public void setHeaderData(byte[] headerData) {
        this.headerData = headerData;
    }
    public byte[] getBodyBytes() {
        return bodyData;
    }
    public void setBodyData(byte[] bodyData) {
        this.bodyData = bodyData;
    }
    /**
     * 获取数据body的string
     *
     * @return
     */
    public String getBodyString() {
        return new String(getBodyBytes(), Charset.forName(EasySocket.getInstance().getDefOptions().getCharsetName()));
    }
    /**
     * 获取完整的数据,包括包头和包体
     *
     * @return
     */
    public byte[] getOriginDataBytes() {
        return Utils.concatBytes(getHeaderData(), getBodyBytes());
    }
}
easysocket/src/main/java/com/easysocket/entity/SocketAddress.java
New file
@@ -0,0 +1,54 @@
package com.easysocket.entity;
/**
 * Author:Alex
 * Date:2019/5/31
 * Note:socket主机地址
 */
public class SocketAddress {
    /**
     * IPV4地址
     */
    private String ip;
    /**
     * 连接服务器端口号
     */
    private int port;
    /**
     * 当此IP地址Ping不通时的备用IP
     */
    private SocketAddress backupAddress;
    /**
     * 获取备用的Ip和端口号
     *
     * @return 备用的端口号和IP地址
     */
    public SocketAddress getBackupAddress() {
        return backupAddress;
    }
    /**
     * 设置备用的IP和端口号,可以不设置
     *
     * @param backupAddress 备用的IP和端口号信息
     */
    public void setBackupAddress(SocketAddress backupAddress) {
        this.backupAddress = backupAddress;
    }
    public SocketAddress(String ip, int port){
        this.ip =ip;
        this.port =port;
    }
    public String getIp() {
        return ip;
    }
    public int getPort() {
        return port;
    }
}
easysocket/src/main/java/com/easysocket/entity/basemsg/IResponse.java
New file
@@ -0,0 +1,9 @@
package com.easysocket.entity.basemsg;
/**
 * Author:Alex
 * Date:2019/12/8
 * Note:
 */
public interface IResponse {
}
easysocket/src/main/java/com/easysocket/entity/basemsg/ISender.java
New file
@@ -0,0 +1,11 @@
package com.easysocket.entity.basemsg;
import java.io.Serializable;
/**
 * Author:Alex
 * Date:2019/6/1
 * Note:发送数据的接口
 */
public interface ISender extends Serializable {
}
easysocket/src/main/java/com/easysocket/entity/basemsg/SuperCallbackResponse.java
New file
@@ -0,0 +1,13 @@
package com.easysocket.entity.basemsg;
/**
 * Author:Alex
 * Date:2019/12/7
 */
public abstract class SuperCallbackResponse implements IResponse {
    public abstract String getCallbackId();
    public abstract void setCallbackId(String callbackId);
}
easysocket/src/main/java/com/easysocket/entity/basemsg/SuperCallbackSender.java
New file
@@ -0,0 +1,36 @@
package com.easysocket.entity.basemsg;
import com.easysocket.utils.Utils;
/**
 * Author:Alex
 * Date:2019/10/19
 */
public abstract class SuperCallbackSender extends SuperSender {
    private String callbackId;
    public SuperCallbackSender() {
        generateCallbackId();
    }
    public String getCallbackId() {
        return callbackId;
    }
    /**
     * 根据自己的协议打包消息
     *
     * @return
     */
    public abstract byte[] pack();
    /**
     * 随机生成一个回调标识 CallbackId,在消息发送前执行,CallbackId作为消息的唯一标识一起传给服务器,服务器反馈
     * 当前消息的时候也是携带同样的CallbackId给客户端,用以识别
     */
    public void generateCallbackId() {
        callbackId= Utils.getRandomChar(20);
    }
}
easysocket/src/main/java/com/easysocket/entity/basemsg/SuperSender.java
New file
@@ -0,0 +1,9 @@
package com.easysocket.entity.basemsg;
/**
 * Author:Alex
 * Date:2019/10/19
 * Note:基础消息
 */
public class SuperSender implements ISender {
}
easysocket/src/main/java/com/easysocket/exception/InitialExeption.java
New file
@@ -0,0 +1,12 @@
package com.easysocket.exception;
/**
 * Author:Alex
 * Date:2019/6/5
 * Note:初始化异常
 */
public class InitialExeption extends RuntimeException{
    public InitialExeption(String s){
        super(s);
    }
}
easysocket/src/main/java/com/easysocket/exception/NotNullException.java
New file
@@ -0,0 +1,12 @@
package com.easysocket.exception;
/**
 * Author:Alex
 * Date:2019/6/5
 * Note:非空异常
 */
public class NotNullException extends RuntimeException {
    public NotNullException(String e) {
        super(e);
    }
}
easysocket/src/main/java/com/easysocket/exception/ReadRecoverableExeption.java
New file
@@ -0,0 +1,13 @@
package com.easysocket.exception;
/**
 * Author:Alex
 * Date:2019/6/5
 * Note:可恢复socket读数据异常
 */
public class ReadRecoverableExeption extends Exception {
    public ReadRecoverableExeption(String s){
        super(s);
    }
}
easysocket/src/main/java/com/easysocket/exception/ReadUnrecoverableException.java
New file
@@ -0,0 +1,12 @@
package com.easysocket.exception;
/**
 * Author:Mapogo
 * Date:2020/12/29
 * Note:不可修复的读取错误
 */
public class ReadUnrecoverableException extends Exception {
    public ReadUnrecoverableException(String s) {
        super(s);
    }
}
easysocket/src/main/java/com/easysocket/exception/RequestCancelException.java
New file
@@ -0,0 +1,13 @@
package com.easysocket.exception;
/**
 * Author:Alex
 * Date:2019/6/4
 * Note:请求取消异常
 */
public class RequestCancelException extends Exception{
    public RequestCancelException(String s){
        super(s);
    }
}
easysocket/src/main/java/com/easysocket/exception/RequestTimeOutException.java
New file
@@ -0,0 +1,13 @@
package com.easysocket.exception;
/**
 * Author:Alex
 * Date:2019/6/4
 * Note:请求超时异常
 */
public class RequestTimeOutException extends Exception{
    public RequestTimeOutException(String s){
        super(s);
    }
}
easysocket/src/main/java/com/easysocket/interfaces/callback/ICallBack.java
New file
@@ -0,0 +1,18 @@
package com.easysocket.interfaces.callback;
import com.easysocket.callback.SuperCallBack;
/**
 * Author:Alex
 * Date:2019/6/5
 * Note:
 */
public interface ICallBack {
    /**
     * socket请求回调
     * @param callBack
     */
    void onCallBack(SuperCallBack callBack);
}
easysocket/src/main/java/com/easysocket/interfaces/callback/IProgressDialog.java
New file
@@ -0,0 +1,26 @@
/*
 * Copyright (C) 2017 zhouyou(478319399@qq.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.easysocket.interfaces.callback;
import android.app.Dialog;
/**
 * <p>描述:自定义对话框的dialog</p>
 */
public interface IProgressDialog {
    Dialog getDialog();
}
easysocket/src/main/java/com/easysocket/interfaces/callback/IType.java
New file
@@ -0,0 +1,29 @@
/*
 * Copyright (C) 2017 zhouyou(478319399@qq.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.easysocket.interfaces.callback;
import java.lang.reflect.Type;
/**
 * <p>描述:获取类型接口</p>
 */
public interface IType<T> {
    Type getType();
    Class<?> getGenericityClazz();
}
easysocket/src/main/java/com/easysocket/interfaces/callback/ProgressCancelListener.java
New file
@@ -0,0 +1,24 @@
/*
 * Copyright (C) 2017 zhouyou(478319399@qq.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.easysocket.interfaces.callback;
/**
 * <p>描述:进度框取消监听</p>
 */
public interface ProgressCancelListener {
    void onCancelProgress();
}
easysocket/src/main/java/com/easysocket/interfaces/config/IConnectionSwitchListener.java
New file
@@ -0,0 +1,13 @@
package com.easysocket.interfaces.config;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.conn.IConnectionManager;
/**
 * Author:Alex
 * Date:2019/6/4
 * Note:
 */
public interface IConnectionSwitchListener {
    void onSwitchConnectionInfo(IConnectionManager manager, SocketAddress oldAddress, SocketAddress newAddress);
}
easysocket/src/main/java/com/easysocket/interfaces/config/IMessageProtocol.java
New file
@@ -0,0 +1,20 @@
package com.easysocket.interfaces.config;
import java.nio.ByteOrder;
/**
 * 消息数据格式
 */
public interface IMessageProtocol {
    /**
     * 获取包头的长度
     */
    int getHeaderLength();
    /**
     * 获取数据包体的长度,根据协议这个长度应该写在包头中,在读取数据时用到
     */
    int getBodyLength(byte[] header, ByteOrder byteOrder);
}
easysocket/src/main/java/com/easysocket/interfaces/config/IOptions.java
New file
@@ -0,0 +1,22 @@
package com.easysocket.interfaces.config;
import com.easysocket.config.EasySocketOptions;
/**
 * Author:Alex
 * Date:2019/6/1
 * Note:
 */
public interface IOptions<T> {
    /**
     * 设置配置信息
     * @param socketOptions
     */
    T setOptions(EasySocketOptions socketOptions);
    /**
     * 获取配置信息
     * @return
     */
    EasySocketOptions getOptions();
}
easysocket/src/main/java/com/easysocket/interfaces/conn/IConnectionManager.java
New file
@@ -0,0 +1,65 @@
package com.easysocket.interfaces.conn;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.callback.ICallBack;
import com.easysocket.interfaces.config.IOptions;
import java.io.InputStream;
import java.io.OutputStream;
/**
 * Author:Alex
 * Date:2019/5/29
 * Note:连接管理的接口规范
 */
public interface IConnectionManager extends ISubscribeSocketAction, IOptions<IConnectionManager>,ISend, ICallBack {
    /**
     * 开始连接
     */
    void connect();
    /**
     * 关闭连接
     * @param isNeedReconnect 是否需要重连
     */
    void disconnect(boolean isNeedReconnect);
    /**
     * 获取socket连接状态
     * @return
     */
    int getConnectionStatus();
    /**
     * 是否可连接的
     * @return
     */
    boolean isConnectViable();
    /**
     * 切换host
     * @param socketAddress
     */
    void switchHost(SocketAddress socketAddress);
    /**
     * 获取输入流
     * @return
     */
    InputStream getInputStream();
    /**
     * 获取输出流
     * @return
     */
    OutputStream getOutStream();
    /**
     * 获取心跳管理器
     * @return
     */
    IHeartManager getHeartManager();
}
easysocket/src/main/java/com/easysocket/interfaces/conn/IHeartManager.java
New file
@@ -0,0 +1,28 @@
package com.easysocket.interfaces.conn;
import com.easysocket.connection.heartbeat.HeartManager;
/**
 * Author:Alex
 * Date:2019/12/8
 * Note:
 */
public interface IHeartManager {
    /**
     * 开始心跳
     * @param clientHeart
     */
    void startHeartbeat(byte[] clientHeart, HeartManager.HeartbeatListener listener);
    /**
     * 停止心跳
     */
    void stopHeartbeat();
    /**
     * 接收到心跳
     */
    void onReceiveHeartBeat();
}
easysocket/src/main/java/com/easysocket/interfaces/conn/IReconnListener.java
New file
@@ -0,0 +1,20 @@
package com.easysocket.interfaces.conn;
/**
 * Author:Alex
 * Date:2019/6/1
 * Note:
 */
public interface IReconnListener {
    /**
     * 关联连接器
     * @param iConnectionManager
     */
    void attach(IConnectionManager iConnectionManager);
    /**
     * 分离连接器
     */
    void detach();
}
easysocket/src/main/java/com/easysocket/interfaces/conn/ISend.java
New file
@@ -0,0 +1,25 @@
package com.easysocket.interfaces.conn;
import com.easysocket.entity.basemsg.SuperCallbackSender;
/**
 * Author:Alex
 * Date:2019/6/5
 * Note:发送接口
 */
public interface ISend {
    /**
     * 发送一个有回调的消息
     * @param sender
     * @return
     */
    IConnectionManager upCallbackMessage(SuperCallbackSender sender);
    /**
     * 发送bytes
     * @param bytes
     * @return
     */
    IConnectionManager upBytes(byte[] bytes);
}
easysocket/src/main/java/com/easysocket/interfaces/conn/ISocketActionDispatch.java
New file
@@ -0,0 +1,38 @@
package com.easysocket.interfaces.conn;
import java.io.Serializable;
/**
 * Author:Alex
 * Date:2019/6/1
 * Note:socket行为分发接口
 */
public interface ISocketActionDispatch {
    /**
     * 停止分发线程
     */
    void stopDispatchThread();
    void startDispatchThread();
    void dispatchAction(String action);
    /**
     * socket行为的分发
     * @param action
     * @param serializable
     */
    void dispatchAction(String action, Serializable serializable);
    /**
     * 订阅socket行为
     * @param iSocketActionListener
     */
    void subscribe(ISocketActionListener iSocketActionListener);
    /**
     * 解除socket行为的订阅
     * @param iSocketActionListener
     */
    void unsubscribe(ISocketActionListener iSocketActionListener);
}
easysocket/src/main/java/com/easysocket/interfaces/conn/ISocketActionListener.java
New file
@@ -0,0 +1,52 @@
package com.easysocket.interfaces.conn;
import com.easysocket.entity.OriginReadData;
import com.easysocket.entity.SocketAddress;
/**
 * Author:Alex
 * Date:2019/6/1
 * Note:socket行为监听接口
 */
public interface ISocketActionListener {
    /**
     * socket连接成功
     * @param socketAddress
     */
    void onSocketConnSuccess(SocketAddress socketAddress);
    /**
     * socket连接失败
     * @param socketAddress
     * @param isNeedReconnect 是否需要重连
     */
    void onSocketConnFail(SocketAddress socketAddress, boolean isNeedReconnect);
    /**
     * 断开socket连接
     * @param socketAddress
     * @param isNeedReconnect 是否需要重连
     */
    void onSocketDisconnect(SocketAddress socketAddress, boolean isNeedReconnect);
    /**
     * socket数据响应
     * @param socketAddress
     * @param originReadData
     */
    void onSocketResponse(SocketAddress socketAddress, OriginReadData originReadData);
    /**
     * socket数据响应
     * @param socketAddress
     * @param readData
     */
    void onSocketResponse(SocketAddress socketAddress, String readData);
    /**
     * socket数据响应
     * @param socketAddress
     * @param readData
     */
    void onSocketResponse(SocketAddress socketAddress, byte[] readData);
}
easysocket/src/main/java/com/easysocket/interfaces/conn/ISubscribeSocketAction.java
New file
@@ -0,0 +1,20 @@
package com.easysocket.interfaces.conn;
/**
 * Author:Alex
 * Date:2019/6/1
 * Note:订阅监听socket
 */
public interface ISubscribeSocketAction {
    /**
     * 注册监听socket的行为
     * @param iSocketActionListener
     */
    void subscribeSocketAction(ISocketActionListener iSocketActionListener);
    /**
     * 注销监听socket的行为
     * @param iSocketActionListener
     */
    void unSubscribeSocketAction(ISocketActionListener iSocketActionListener);
}
easysocket/src/main/java/com/easysocket/interfaces/conn/SocketActionListener.java
New file
@@ -0,0 +1,57 @@
package com.easysocket.interfaces.conn;
import com.easysocket.entity.OriginReadData;
import com.easysocket.entity.SocketAddress;
/**
 * Author:Alex
 * Date:2019/6/4
 * Note:socket行为监听的抽象类,继承此类可以选择性地重写方法
 */
public abstract class SocketActionListener implements ISocketActionListener{
    /**
     * socket连接成功
     * @param socketAddress
     */
    @Override
    public void onSocketConnSuccess(SocketAddress socketAddress) {
    }
    /**
     * socket连接失败
     * @param socketAddress
     * @param isNeedReconnect 是否需要重连
     */
    @Override
    public void onSocketConnFail(SocketAddress socketAddress, boolean isNeedReconnect) {
    }
    /**
     * 断开socket连接
     * @param socketAddress
     * @param isNeedReconnect 是否需要重连
     */
    @Override
    public void onSocketDisconnect(SocketAddress socketAddress, boolean isNeedReconnect) {
    }
    /**
     * socket读数据反馈
     * @param socketAddress
     * @param originReadData
     */
    @Override
    public void onSocketResponse(SocketAddress socketAddress, OriginReadData originReadData) {
    }
    @Override
    public void onSocketResponse(SocketAddress socketAddress, byte[] readData) {
    }
    @Override
    public void onSocketResponse(SocketAddress socketAddress, String readData) {
    }
}
easysocket/src/main/java/com/easysocket/interfaces/io/IIOManager.java
New file
@@ -0,0 +1,27 @@
package com.easysocket.interfaces.io;
/**
 * Author:Alex
 * Date:2019/6/1
 * Note:
 */
public interface IIOManager {
    /**
     * 发送字节流
     *
     * @param bytes
     */
    void sendBytes(byte[] bytes);
    /**
     * 关闭io管理器
     */
    void closeIO();
    /**
     * 开启io操作
     */
    void startIO();
}
easysocket/src/main/java/com/easysocket/interfaces/io/IReader.java
New file
@@ -0,0 +1,32 @@
package com.easysocket.interfaces.io;
/**
 * Author:Alex
 * Date:2019/6/1
 * Note:
 */
public interface IReader<T> {
    /**
     * 读数据
     */
    void read() throws Exception;
    /**
     * 打开数据的读取
     */
    void openReader();
    /**
     * 关闭数据的读取
     */
    void closeReader();
    /**
     * 设置参数
     * @param t
     */
    void setOption(T t);
}
easysocket/src/main/java/com/easysocket/interfaces/io/IWriter.java
New file
@@ -0,0 +1,38 @@
package com.easysocket.interfaces.io;
import java.io.IOException;
/**
 * Author:Alex
 * Date:2019/6/1
 * Note:
 */
public interface IWriter<T> {
    /**
     * 保存要写的数据
     */
    void offer(byte[] sender);
    /**
     * 写数据
     * @param sender
     */
    void write(byte[] sender) throws IOException;
    /**
     * 关闭stream
     */
    void closeWriter();
    /**
     * 开启写数据
     */
    void openWriter();
    /**
     * 设置参数
     * @param t
     */
    void setOption(T t);
}
easysocket/src/main/java/com/easysocket/utils/HexUtil.java
New file
@@ -0,0 +1,275 @@
package com.easysocket.utils;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
 * Copyright (C), 2022,
 * Author: zuo
 * Date: 2022/3/9 14:55
 * Description:
 */
public class HexUtil {
    /**
     * hex字符串转byte数组
     *
     * @param inHex 待转换的Hex字符串
     * @return 转换后的byte数组结果
     */
    public static byte[] hexToByteArray(String inHex) {
        int hexlen = inHex.length();
        byte[] result;
        if (hexlen % 2 == 1) {
            //奇数
            hexlen++;
            result = new byte[(hexlen / 2)];
            inHex = "0" + inHex;
        } else {
            //偶数
            result = new byte[(hexlen / 2)];
        }
        int j = 0;
        for (int i = 0; i < hexlen; i += 2) {
            result[j] = hexToByte(inHex.substring(i, i + 2));
            j++;
        }
        return result;
    }
    /**
     * Hex字符串转byte
     *
     * @param inHex 待转换的Hex字符串
     * @return 转换后的byte
     */
    public static byte hexToByte(String inHex) {
        return (byte) Integer.parseInt(inHex, 16);
    }
    /**
     * 字节转十六进制
     *
     * @param b 需要进行转换的byte字节
     * @return 转换后的Hex字符串
     */
    public static String byteToHex(byte b) {
        String hex = Integer.toHexString(b & 0xFF);
        if (hex.length() < 2) {
            hex = "0" + hex;
        }
        return hex.toUpperCase();
    }
    /**
     * 字节数组转16进制
     *
     * @param bytes 需要转换的byte数组
     * @return 转换后的Hex字符串
     */
    public static String bytesToHex(byte[] bytes) {
        try {
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < bytes.length; i++) {
                String hex = Integer.toHexString(bytes[i] & 0xFF);
                if (hex.length() < 2) {
                    sb.append(0);
                }
                sb.append(hex);
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
    public static String byteArrayToHexString(byte[] byteArray) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : byteArray) {
            // 将字节转换为无符号整数
            int unsignedInt = b & 0xff;
            // 将无符号整数转换为16进制字符串
            String hex = Integer.toHexString(unsignedInt);
            // 如果字符串长度小于2,在前面补0
            if (hex.length() < 2) {
                hex = "0" + hex;
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
    /**
     * 字节数组转16进制 不在末尾添加0
     *
     * @param bytes 需要转换的byte数组
     * @return 转换后的Hex字符串
     */
    public static String bytesToHexNoAddZero(byte[] bytes) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            sb.append(hex);
        }
        return sb.toString();
    }
    /**
     * 将 4字节的16进制字符串,转换为32位带符号的十进制浮点型
     *
     * @param str 4字节 16进制字符
     * @return
     */
    public static float hexToFloat(String str) {
        return Float.intBitsToFloat(new BigInteger(str, 16).intValue());
    }
    /**
     * 将带符号的32位浮点数装换为16进制
     *
     * @param value
     * @return
     */
    public static String folatToHexString(Float value) {
        return Integer.toHexString(Float.floatToIntBits(value));
    }
    /**
     * 十进制转16进制
     *
     * @param number
     * @return
     */
    public static String get10to16(int number) {
        return Integer.toHexString(number);
    }
    /**
     * 十进制转16进制 补齐偶数 高位在前低位在后
     *
     * @param number
     * @return
     */
    public static String get10to16CompleteHex(int number) {
        String hex = Integer.toHexString(number);
        if (hex.length() % 2 == 0) {
            return hex;
        } else {
            return "0" + hex;
        }
    }
    /**
     * 十进制转16进制低位在前高位在后
     *
     * @param number 十进制数
     * @param length 补足多少位
     * @return
     */
    public static String get10to16LowHigh(int number, int length) {
        String str = "";
        try {
            str = Integer.toHexString(number);
            str = getHexToLenght(str, length);
            str = spaceHex(str);
            str = HighLowHex(str);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }
    /**
     * 16进制转10进制高低位转换
     *
     * @param hex
     * @return
     */
    public static int get16to10LowHigh(String hex) {
        try {
            String str = "";
            str = spaceHex(hex);
            str = HighLowHex(str);
            return Integer.parseInt(str, 16);
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        return 0;
    }
    /**
     * 返回特定长度的16进制字符串
     *
     * @param data
     * @param length
     * @return
     */
    public static String getHexToLenght(String data, int length) {
        StringBuffer stringBuilder = new StringBuffer(data);
        for (int i = 0; i < length - data.length(); i++) {
            stringBuilder.insert(0, "0");
        }
        return stringBuilder.toString();
    }
    /**
     * 十六进制数隔空位
     *
     * @param str
     * @return
     */
    public static String spaceHex(String str) {
        char[] array = str.toCharArray();
        if (str.length() <= 2) return str;
        StringBuffer bufferHex = new StringBuffer();
        for (int i = 0; i < array.length; i++) {
            int start = i + 1;
            if (start % 2 == 0) {
                bufferHex.append(array[i]).append(" ");
            } else {
                bufferHex.append(array[i]);
            }
        }
        return bufferHex.toString();
    }
    /**
     * 高位16进制转低位
     *
     * @param str
     * @return
     */
    private static String HighLowHex(String str) {
        if (str.trim().length() <= 2) return str;
        List<String> list = Arrays.asList(str.split(" "));
        Collections.reverse(list);
        StringBuffer stringBuffer = new StringBuffer();
        for (String string : list) {
            stringBuffer.append(string);
        }
        return stringBuffer.toString();
    }
    /**
     * @param hex
     * @return
     */
    public static int get16to10(String hex) {
        int x = 0;
        try {
            x = Integer.parseInt(hex, 16);
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        return x;
    }
}
easysocket/src/main/java/com/easysocket/utils/LogUtil.java
New file
@@ -0,0 +1,87 @@
package com.easysocket.utils;
import android.util.Log;
import com.easysocket.EasySocket;
public class LogUtil {
    public static final String LOGTAG = "easysocket";
    public static boolean debugEnabled = EasySocket.getInstance().getDefOptions().isDebug();
    public LogUtil() {
    }
    private static String getDebugInfo() {
        Throwable stack = new Throwable().fillInStackTrace();
        StackTraceElement[] trace = stack.getStackTrace();
        int n = 2;
        return trace[n].getClassName() + " " + trace[n].getMethodName() + "()" + ":" + trace[n].getLineNumber() +
                " ";
    }
    private static String getLogInfoByArray(String[] infos) {
        StringBuilder sb = new StringBuilder();
        for (String info : infos) {
            sb.append(info);
            sb.append(" ");
        }
        return sb.toString();
    }
    public static void i(String... s) {
        if (debugEnabled) {
            i(LOGTAG, getDebugInfo() + getLogInfoByArray(s));
        }
    }
    public static void e(Throwable tr) {
        if (debugEnabled) {
            Log.e(LOGTAG, getDebugInfo() ,tr);
        }
    }
    public static void e(String... s) {
        if (debugEnabled) {
            e(LOGTAG, getDebugInfo() + getLogInfoByArray(s));
        }
    }
    public static void d(String... s) {
        if (debugEnabled) {
            d(LOGTAG, getDebugInfo() + getLogInfoByArray(s));
        }
    }
    public static void v(String... s) {
        if (debugEnabled) {
            v(LOGTAG, getDebugInfo() + getLogInfoByArray(s));
        }
    }
    public static void w(String... s) {
        if (debugEnabled) {
            w(LOGTAG, getDebugInfo() + getLogInfoByArray(s));
        }
    }
    private static void i(String name, String log) {
        System.out.println(name + ":" + log);
    }
    private static void d(String name, String log) {
        System.out.println(name + ":" + log);
    }
    private static void v(String name, String log) {
        System.out.println(name + ":" + log);
    }
    private static void e(String name, String log) {
        System.err.println(name + ":" + log);
    }
    private static void w(String name, String log) {
        System.err.println(name + ":" + log);
    }
}
easysocket/src/main/java/com/easysocket/utils/Utils.java
New file
@@ -0,0 +1,149 @@
package com.easysocket.utils;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.os.Looper;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Random;
/**
 * Created by LXR ON 2018/8/30.
 */
public class Utils {
    /**
     * 获取泛型参数的类型
     *
     * @param <T>
     * @return
     */
    public static <T> Type findGenericityType(Class<T> cls) {
        Type genType = cls.getGenericSuperclass(); //返回直接继承的父类(包含泛型参数)类型,如果有泛型T,也要包括进去
        //getActualTypeArguments 获取泛型中的实际类型,比如Map<Sting,String>中的String类型
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        Type type = params[0]; //泛型的实际类型
        Type finalNeedType;
        if (type instanceof ParameterizedType) { //二级泛型,这里就处理最多二级吧,形如 A<B<T>>,两个<>
            finalNeedType = ((ParameterizedType) type).getActualTypeArguments()[0];
        } else { // 一级泛型,形如A<T>
            finalNeedType = type;
        }
        //如果泛型类型还是变量类型,比如T、V之类的,代表没有填写泛型参数
        if (finalNeedType instanceof TypeVariable) throw new IllegalStateException("没有填写泛型参数");
        return finalNeedType;
    }
    /**
     * 字符串是否为空
     *
     * @param str
     * @return
     */
    public static boolean isStringEmpty(String str) {
        return str == null || str.trim().length() == 0;
    }
    /**
     * 生成随机字符串
     *
     * @param length
     * @return
     */
    public static String getRandomChar(int length) {
        char[] chr = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
        Random random = new Random();
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < length; i++) {
            buffer.append(chr[random.nextInt(36)]);
        }
        return buffer.toString();
    }
    /**
     * 获取handler对象
     *
     * @param isMainHandler 是否为主线程的handler,为false时返回的是当前线程handler
     * @return
     */
    public static Handler getHandler(boolean isMainHandler) {
        Handler handler;
        if (isMainHandler) {
            handler = new Handler(Looper.getMainLooper());
        } else {
            Looper.prepare();
            handler = new Handler();
        }
        return handler;
    }
    /**
     * 睡眠多少毫秒
     *
     * @param milliSecond 毫秒
     */
    public static void sleep(long milliSecond) {
        try {
            Thread.sleep(milliSecond);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /**
     * 非空检查
     *
     * @param object
     * @param emsg
     * @throws
     */
    public static void checkNotNull(Object object, String emsg) {
        try {
            if (object == null) {
                throw new Exception(emsg);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void throwNotNull(Object object, String emsg) throws Exception {
        if (object == null) {
            throw new Exception(emsg);
        }
    }
    // 判断是否连接网络
    public static boolean isNetConnected(Context context) {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = cm.getActiveNetworkInfo();
        return info != null && info.isConnected();
    }
    /**
     * 拼接两个byte[]
     *
     * @param
     * @param
     * @return
     */
    public static byte[] concatBytes(byte[] bt1, byte[] bt2) {
        if (bt1 == null) {
            return bt2;
        }
        if (bt2 == null) {
            return bt1;
        }
        byte[] bt3 = new byte[bt1.length + bt2.length];
        System.arraycopy(bt1, 0, bt3, 0, bt1.length);
        System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
        return bt3;
    }
}
settings.gradle
@@ -15,4 +15,4 @@
    }
}
rootProject.name = "chargeQh"
include ':app',':pickerviewlibrary'
include ':app',':pickerviewlibrary',':easysocket'