From 4d2d9239d8915a030bb84cb2147774470b04bf27 Mon Sep 17 00:00:00 2001
From: zuoxiao <470321431@qq.com>
Date: 星期一, 04 三月 2024 17:21:11 +0800
Subject: [PATCH] 先上传Socket通讯相关代码 密码卡相关代码
---
easysocket/src/main/java/com/easysocket/interfaces/conn/ISocketActionDispatch.java | 38
easysocket/src/main/java/com/easysocket/connection/heartbeat/HeartManager.java | 181 ++
easysocket/src/main/AndroidManifest.xml | 4
easysocket/src/main/java/com/easysocket/interfaces/config/IMessageProtocol.java | 20
easysocket/src/main/java/com/easysocket/config/EasySocketOptions.java | 478 ++++++
easysocket/src/main/java/com/easysocket/interfaces/io/IReader.java | 32
easysocket/src/main/java/com/easysocket/exception/InitialExeption.java | 12
app/src/main/java/com/dayu/recharge/card/RegionCard.java | 2
easysocket/src/main/java/com/easysocket/entity/OriginReadData.java | 58
app/src/main/java/com/dayu/recharge/activity/SysActivity.java | 31
easysocket/src/main/java/com/easysocket/config/SocketFactory.java | 14
easysocket/src/main/java/com/easysocket/entity/basemsg/SuperCallbackResponse.java | 13
easysocket/src/main/java/com/easysocket/ConnectionHolder.java | 138 +
easysocket/src/main/java/com/easysocket/interfaces/config/IConnectionSwitchListener.java | 13
easysocket/src/main/java/com/easysocket/connection/action/IOAction.java | 11
easysocket/src/main/java/com/easysocket/interfaces/callback/IType.java | 29
app/build.gradle | 2
easysocket/src/main/java/com/easysocket/interfaces/callback/ICallBack.java | 18
easysocket/src/main/java/com/easysocket/connection/reconnect/DefaultReConnection.java | 148 +
easysocket/src/main/java/com/easysocket/interfaces/io/IIOManager.java | 27
easysocket/src/main/java/com/easysocket/connection/action/SocketAction.java | 15
easysocket/src/main/java/com/easysocket/exception/RequestTimeOutException.java | 13
easysocket/src/main/java/com/easysocket/entity/basemsg/SuperCallbackSender.java | 36
app/src/main/java/com/dayu/recharge/activity/HomeActivity.java | 1
easysocket/src/main/java/com/easysocket/interfaces/callback/ProgressCancelListener.java | 24
easysocket/build.gradle | 29
easysocket/src/main/java/com/easysocket/utils/LogUtil.java | 87 +
easysocket/src/main/java/com/easysocket/connection/dispatcher/SocketActionDispatcher.java | 221 ++
app/src/main/res/layout/activity_parameter.xml | 14
easysocket/src/main/java/com/easysocket/connection/dispatcher/CallbackResponseDispatcher.java | 191 ++
easysocket/src/main/java/com/easysocket/config/DefaultX509ProtocolTrustManager.java | 28
easysocket/src/main/java/com/easysocket/connection/reconnect/AbsReconnection.java | 52
easysocket/src/main/java/com/easysocket/exception/NotNullException.java | 12
easysocket/src/main/java/com/easysocket/interfaces/callback/IProgressDialog.java | 26
easysocket/src/main/java/com/easysocket/config/CallbackIDFactory.java | 18
easysocket/src/main/java/com/easysocket/entity/basemsg/SuperSender.java | 9
easysocket/src/main/java/com/easysocket/interfaces/conn/IConnectionManager.java | 65
easysocket/src/main/java/com/easysocket/interfaces/conn/IHeartManager.java | 28
easysocket/src/main/java/com/easysocket/interfaces/conn/ISend.java | 25
easysocket/src/main/java/com/easysocket/entity/SocketAddress.java | 54
easysocket/src/main/java/com/easysocket/callback/ProgressDialogCallBack.java | 116 +
easysocket/src/main/java/com/easysocket/connection/iowork/EasyWriter.java | 151 +
easysocket/src/main/java/com/easysocket/exception/ReadRecoverableExeption.java | 13
easysocket/src/main/java/com/easysocket/connection/iowork/EasyReader.java | 337 ++++
easysocket/src/main/java/com/easysocket/connection/iowork/IOManager.java | 98 +
easysocket/src/main/java/com/easysocket/entity/basemsg/ISender.java | 11
easysocket/src/main/java/com/easysocket/callback/SimpleCallBack.java | 29
easysocket/src/main/java/com/easysocket/utils/Utils.java | 149 +
easysocket/src/main/java/com/easysocket/connection/connect/TcpConnection.java | 141 +
easysocket/src/main/java/com/easysocket/entity/basemsg/IResponse.java | 9
easysocket/src/main/java/com/easysocket/config/DefaultMessageProtocol.java | 28
app/src/main/java/com/dayu/recharge/activity/ParameterActivity.java | 8
easysocket/src/main/java/com/easysocket/interfaces/conn/ISocketActionListener.java | 52
settings.gradle | 2
easysocket/src/main/java/com/easysocket/EasySocket.java | 340 ++++
easysocket/src/main/java/com/easysocket/interfaces/conn/ISubscribeSocketAction.java | 20
app/src/main/AndroidManifest.xml | 1
easysocket/src/main/java/com/easysocket/interfaces/io/IWriter.java | 38
easysocket/src/main/java/com/easysocket/callback/SuperCallBack.java | 44
app/src/main/java/com/dayu/recharge/card/PassWordCard.java | 13
easysocket/src/main/java/com/easysocket/config/SocketSSLConfig.java | 81 +
easysocket/src/main/java/com/easysocket/interfaces/conn/IReconnListener.java | 20
easysocket/src/main/java/com/easysocket/connection/action/SocketStatus.java | 17
app/src/main/res/layout/activity_admin.xml | 38
easysocket/src/main/java/com/easysocket/connection/dispatcher/MainThreadExecutor.java | 21
easysocket/src/main/java/com/easysocket/exception/RequestCancelException.java | 13
easysocket/src/main/java/com/easysocket/connection/connect/SuperConnection.java | 356 ++++
easysocket/src/main/java/com/easysocket/exception/ReadUnrecoverableException.java | 12
easysocket/src/main/java/com/easysocket/interfaces/conn/SocketActionListener.java | 57
easysocket/src/main/java/com/easysocket/utils/HexUtil.java | 275 +++
easysocket/src/main/java/com/easysocket/interfaces/config/IOptions.java | 22
71 files changed, 4,722 insertions(+), 7 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 9f64280..390c27d 100644
--- a/app/build.gradle
+++ b/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')
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 39721f4..a90c515 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/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
diff --git a/app/src/main/java/com/dayu/recharge/activity/HomeActivity.java b/app/src/main/java/com/dayu/recharge/activity/HomeActivity.java
index 33d033f..8ea87ae 100644
--- a/app/src/main/java/com/dayu/recharge/activity/HomeActivity.java
+++ b/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) {
diff --git a/app/src/main/java/com/dayu/recharge/activity/ParameterActivity.java b/app/src/main/java/com/dayu/recharge/activity/ParameterActivity.java
index 283e26a..1838e59 100644
--- a/app/src/main/java/com/dayu/recharge/activity/ParameterActivity.java
+++ b/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);
+ }
+ });
}
}
diff --git a/app/src/main/java/com/dayu/recharge/activity/SysActivity.java b/app/src/main/java/com/dayu/recharge/activity/SysActivity.java
index 5bffa64..d3222ec 100644
--- a/app/src/main/java/com/dayu/recharge/activity/SysActivity.java
+++ b/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) {
+
+ }
+ });
}
diff --git a/app/src/main/java/com/dayu/recharge/card/PassWordCard.java b/app/src/main/java/com/dayu/recharge/card/PassWordCard.java
index 40d038b..dfb7f81 100644
--- a/app/src/main/java/com/dayu/recharge/card/PassWordCard.java
+++ b/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){
diff --git a/app/src/main/java/com/dayu/recharge/card/RegionCard.java b/app/src/main/java/com/dayu/recharge/card/RegionCard.java
index 8656269..9adf9b7 100644
--- a/app/src/main/java/com/dayu/recharge/card/RegionCard.java
+++ b/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 {
diff --git a/app/src/main/res/layout/activity_admin.xml b/app/src/main/res/layout/activity_admin.xml
index 6e87394..ca72490 100644
--- a/app/src/main/res/layout/activity_admin.xml
+++ b/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>
diff --git a/app/src/main/res/layout/activity_parameter.xml b/app/src/main/res/layout/activity_parameter.xml
index f59a95d..30d7690 100644
--- a/app/src/main/res/layout/activity_parameter.xml
+++ b/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" />
diff --git a/easysocket/build.gradle b/easysocket/build.gradle
new file mode 100644
index 0000000..34c191c
--- /dev/null
+++ b/easysocket/build.gradle
@@ -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"
diff --git a/easysocket/src/main/AndroidManifest.xml b/easysocket/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e18d960
--- /dev/null
+++ b/easysocket/src/main/AndroidManifest.xml
@@ -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>
diff --git a/easysocket/src/main/java/com/easysocket/ConnectionHolder.java b/easysocket/src/main/java/com/easysocket/ConnectionHolder.java
new file mode 100644
index 0000000..f198f9f
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/ConnectionHolder.java
@@ -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锛欰lex
+ * Date锛�2019/6/4
+ * Note锛歴ocket杩炴帴绠$悊鍣�
+ */
+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]));
+ }
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/EasySocket.java b/easysocket/src/main/java/com/easysocket/EasySocket.java
new file mode 100644
index 0000000..4aecbd3
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/EasySocket.java
@@ -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锛欰lex
+ * Date锛�2019/6/4
+ * Note锛欵asySocket 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杩炴帴锛屾杩炴帴涓洪粯璁ょ殑杩炴帴锛屽鏋滀綘鐨勯」鐩彧鏈変竴涓猄ocket杩炴帴锛屽彲浠ョ敤杩欎釜鏂规硶锛�
+ * 鍦ㄦ柟娉曚笉鎸囧畾杩炴帴鍦板潃鐨勬儏鍐典笅锛岄粯璁や娇鐢ㄩ兘鏄繖涓繛鎺ワ紝
+ * 姣斿锛� 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("璇峰湪鍒濆鍖栫殑鏃跺�欒缃甋ocketAddress");
+ }
+ // 濡傛灉鏈夊鐢ㄤ富鏈哄垯璁剧疆
+ 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鍦板潃锛屽寘鎷琲p鍜岀鍙�
+ * @return
+ */
+ public EasySocket connect(String address) {
+ getConnection(address).connect();
+ return this;
+ }
+
+
+ /**
+ * 鍏抽棴杩炴帴锛屼綔鐢ㄤ簬榛樿杩炴帴
+ *
+ * @param isNeedReconnect 鏄惁闇�瑕侀噸杩�
+ * @return
+ */
+ public EasySocket disconnect(boolean isNeedReconnect) {
+ LogUtil.d("EasySocket--銆媎isconnect");
+ 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--銆媎estroyConnection");
+ // 鏂紑杩炴帴
+ 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);
+ }
+
+
+ /**
+ * 鍙戦�乥yte[]
+ *
+ * @param message
+ * @return
+ */
+ public IConnectionManager upMessage(byte[] message, String address) {
+ return getConnection(address).upBytes(message);
+ }
+
+ /**
+ * 鍙戦�乥yte[]锛屼綔鐢ㄤ簬榛樿杩炴帴
+ *
+ * @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()
+// + "鐨凷ocket鐨勮繛鎺ワ紝璇蜂娇鐢╟om.easysocket.EasySocket.connect()鏂规硶鍒涘缓涓�涓粯璁ょ殑杩炴帴");
+ }
+ return defConnection;
+ }
+
+ /**
+ * 鑾峰彇杩炴帴
+ *
+ * @return
+ */
+ public IConnectionManager getConnection(String address) {
+ IConnectionManager connectionManager = connectionHolder.getConnection(address);
+ if (connectionManager == null) {
+ throw new NotNullException("璇峰厛鍒涘缓锛�" + address + "鐨凷ocket杩炴帴");
+ }
+ return connectionManager;
+ }
+
+ /**
+ * 鍒涘缓鎸囧畾鐨剆ocket杩炴帴锛屽鏋滀綘鐨勯」鐩湁澶氫釜socket杩炴帴锛屽彲浠ョ敤杩欎釜鏂规硶鍒涘缓鏇村鐨勮繛鎺ワ紝
+ * 褰撲綘浣跨敤甯︽湁socket鍦板潃涓哄弬鏁扮殑鏂规硶鐨勬椂鍊欙紝浣滅敤鐨勫氨鏄搴旂殑杩炴帴
+ * 姣斿锛歝onnect(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;
+ }
+
+ /**
+ * 鏄惁涓篸ebug
+ *
+ * @param debug
+ */
+ public void setDebug(boolean debug) {
+ EasySocketOptions.setIsDebug(debug);
+ }
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/callback/ProgressDialogCallBack.java b/easysocket/src/main/java/com/easysocket/callback/ProgressDialogCallBack.java
new file mode 100644
index 0000000..0da1ee9
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/callback/ProgressDialogCallBack.java
@@ -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("缃戠粶璇锋眰琚彇娑�"));
+ }
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/callback/SimpleCallBack.java b/easysocket/src/main/java/com/easysocket/callback/SimpleCallBack.java
new file mode 100644
index 0000000..0e0c0c2
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/callback/SimpleCallBack.java
@@ -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) {
+
+ }
+
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/callback/SuperCallBack.java b/easysocket/src/main/java/com/easysocket/callback/SuperCallBack.java
new file mode 100644
index 0000000..cfbdde4
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/callback/SuperCallBack.java
@@ -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);
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/config/CallbackIDFactory.java b/easysocket/src/main/java/com/easysocket/config/CallbackIDFactory.java
new file mode 100644
index 0000000..623fa5b
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/config/CallbackIDFactory.java
@@ -0,0 +1,18 @@
+package com.easysocket.config;
+
+import com.easysocket.entity.OriginReadData;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/4
+ * Note锛氳鎯冲疄鐜癊asySocket鐨勫洖璋冨姛鑳斤紝蹇呴』瀹炵幇姝ゅ伐鍘傜被锛宑allbackID浣滀负鍥炶皟娑堟伅鐨勫敮涓�鏍囪瘑
+ */
+public abstract class CallbackIDFactory {
+ /**
+ * 杩斿洖callbackID
+ *
+ * @param
+ * @return 濡傛灉娌℃湁callbackID璇疯繑鍥瀗ull
+ */
+ public abstract String getCallbackID(OriginReadData data);
+}
diff --git a/easysocket/src/main/java/com/easysocket/config/DefaultMessageProtocol.java b/easysocket/src/main/java/com/easysocket/config/DefaultMessageProtocol.java
new file mode 100644
index 0000000..7d737f9
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/config/DefaultMessageProtocol.java
@@ -0,0 +1,28 @@
+package com.easysocket.config;
+
+import com.easysocket.interfaces.config.IMessageProtocol;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/5/31
+ * Note锛氶粯璁ょ殑娑堟伅鍗忚锛宧eader涓�4涓瓧鑺傦紝淇濆瓨娑堟伅浣� body鐨勯暱搴�
+ */
+public class DefaultMessageProtocol implements IMessageProtocol {
+ @Override
+ public int getHeaderLength() {
+ return 4; // 鍖呭ご闀垮害锛岀敤鏉ヤ繚瀛榖ody鐨勯暱搴﹀��
+ }
+
+ @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
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/config/DefaultX509ProtocolTrustManager.java b/easysocket/src/main/java/com/easysocket/config/DefaultX509ProtocolTrustManager.java
new file mode 100644
index 0000000..ca7c96e
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/config/DefaultX509ProtocolTrustManager.java
@@ -0,0 +1,28 @@
+package com.easysocket.config;
+
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * Author锛欰lex
+ * 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];
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/config/EasySocketOptions.java b/easysocket/src/main/java/com/easysocket/config/EasySocketOptions.java
new file mode 100644
index 0000000..0cf70b4
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/config/EasySocketOptions.java
@@ -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锛欰lex銆�
+ * Date锛�2019/5/31銆�
+ * Note锛歴ocket鐩稿叧閰嶇疆銆�
+ */
+public class EasySocketOptions {
+
+ /**
+ * 鏄惁璋冭瘯妯″紡
+ */
+ private static boolean isDebug = true;
+ /**
+ * 涓绘満鍦板潃
+ */
+ private SocketAddress socketAddress;
+ /**
+ * 澶囩敤涓绘満鍦板潃
+ */
+ private SocketAddress backupAddress;
+ /**
+ * 鍐欏叆Socket绠¢亾鐨勫瓧鑺傚簭
+ */
+ private ByteOrder writeOrder;
+ /**
+ * 浠嶴ocket璇诲彇瀛楄妭鏃剁殑瀛楄妭搴�
+ */
+ private ByteOrder readOrder;
+ /**
+ * 浠巗ocket璇诲彇鏁版嵁鏃堕伒浠庣殑鏁版嵁鍖呯粨鏋勫崗璁紝鍦ㄤ笟鍔″眰杩涜瀹氫箟
+ */
+ 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;
+ /**
+ * 瀹炵幇鍥炶皟鍔熻兘闇�瑕乧allbackID锛岃�宑allbackID鏄繚瀛樺湪鍙戦�佹秷鎭拰搴旂瓟娑堟伅涓殑锛屾宸ュ巶鐢ㄦ潵鑾峰彇socket娑堟伅涓�
+ * 淇濆瓨callbackID鍊肩殑key锛屾瘮濡俲son鏍煎紡涓殑key-value涓殑key
+ */
+ private CallbackIDFactory callbackIDFactory;
+ /**
+ * 璇锋眰瓒呮椂鏃堕棿锛屽崟浣嶆绉�
+ */
+ private long requestTimeout;
+ /**
+ * 鏄惁寮�鍚姹傝秴鏃舵娴�
+ */
+ private boolean isOpenRequestTimeout;
+
+ /**
+ * IO瀛楃娴佺殑缂栫爜鏂瑰紡锛岄粯璁tf-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;
+ }
+
+ /**
+ * 鑷畾涔夊垱寤簊ocket宸ュ巶
+ *
+ * @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;
+ }
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/config/SocketFactory.java b/easysocket/src/main/java/com/easysocket/config/SocketFactory.java
new file mode 100644
index 0000000..1aebab0
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/config/SocketFactory.java
@@ -0,0 +1,14 @@
+package com.easysocket.config;
+
+import com.easysocket.entity.SocketAddress;
+
+import java.net.Socket;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/5/31
+ * Note锛歴ocket宸ュ巶
+ */
+public abstract class SocketFactory {
+ public abstract Socket createSocket(SocketAddress info, EasySocketOptions options) throws Exception;
+}
diff --git a/easysocket/src/main/java/com/easysocket/config/SocketSSLConfig.java b/easysocket/src/main/java/com/easysocket/config/SocketSSLConfig.java
new file mode 100644
index 0000000..1000cce
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/config/SocketSSLConfig.java
@@ -0,0 +1,81 @@
+package com.easysocket.config;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+/**
+ * socket鐨剆sl閰嶇疆
+ */
+
+public class SocketSSLConfig {
+ /**
+ * 瀹夊叏鍗忚鍚嶇О(缂虹渷涓篠SL)
+ */
+ private String mProtocol;
+ /**
+ * 淇′换璇佷功绠$悊鍣�(缂虹渷涓篨509)
+ */
+ private TrustManager[] mTrustManagers;
+ /**
+ * 璇佷功绉橀挜绠$悊鍣�(缂虹渷涓簄ull)
+ */
+ private KeyManager[] mKeyManagers;
+ /**
+ * 鑷畾涔塖SLFactory(缂虹渷涓簄ull)
+ */
+ 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;
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/connection/action/IOAction.java b/easysocket/src/main/java/com/easysocket/connection/action/IOAction.java
new file mode 100644
index 0000000..4caf13a
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/connection/action/IOAction.java
@@ -0,0 +1,11 @@
+package com.easysocket.connection.action;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/3
+ * Note锛�
+ */
+public interface IOAction {
+ // 鏀跺埌娑堟伅鍝嶅簲
+ String ACTION_READ_COMPLETE = "action_read_complete";
+}
diff --git a/easysocket/src/main/java/com/easysocket/connection/action/SocketAction.java b/easysocket/src/main/java/com/easysocket/connection/action/SocketAction.java
new file mode 100644
index 0000000..f9619c8
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/connection/action/SocketAction.java
@@ -0,0 +1,15 @@
+package com.easysocket.connection.action;
+
+/**
+ * Author锛欰lex
+ * 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";
+}
diff --git a/easysocket/src/main/java/com/easysocket/connection/action/SocketStatus.java b/easysocket/src/main/java/com/easysocket/connection/action/SocketStatus.java
new file mode 100644
index 0000000..3918289
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/connection/action/SocketStatus.java
@@ -0,0 +1,17 @@
+package com.easysocket.connection.action;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/1
+ * Note锛氳繛鎺ョ姸鎬�
+ */
+public interface SocketStatus {
+ // 宸叉柇寮�杩炴帴
+ int SOCKET_DISCONNECTED = 0;
+ // 姝e湪杩炴帴
+ int SOCKET_CONNECTING = 1;
+ // 宸茶繛鎺�
+ int SOCKET_CONNECTED = 2;
+ // 姝e湪鏂紑杩炴帴
+ int SOCKET_DISCONNECTING =3;
+}
diff --git a/easysocket/src/main/java/com/easysocket/connection/connect/SuperConnection.java b/easysocket/src/main/java/com/easysocket/connection/connect/SuperConnection.java
new file mode 100644
index 0000000..af5491a
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/connection/connect/SuperConnection.java
@@ -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锛欰lex
+ * Date锛�2019/5/29
+ * Note锛歴ocket杩炴帴鐨勮秴绫�
+ */
+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>>姝e湪鏂紑杩炴帴锛屽欢鏃朵竴绉掑煼琛岄噸杩�");
+ connect();
+ }
+ }, 1000); // 寤舵椂1绉�
+ return;
+ }
+ LogUtil.d("---> socket寮�濮嬭繛鎺�");
+ if (socketAddress.getIp() == null) {
+ throw new NotNullException("璇锋鏌ユ槸鍚﹁缃簡IP鍦板潃");
+ }
+ // 姝e湪杩炴帴
+ 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;
+ }
+ // 姝e湪閲嶈繛涓�
+ if (isNeedReconnect && reconnection.isReconning()) {
+ return;
+ }
+ // 姝e湪鏂紑杩炴帴
+ 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);
+ }
+
+ // 寮�鍚痵ocket鐩稿叧绠$悊鍣�
+ private void openSocketManager() {
+ if (callbackResponseDispatcher == null)
+ callbackResponseDispatcher = new CallbackResponseDispatcher(this);
+ if (ioManager == null) {
+ ioManager = new IOManager(this, actionDispatcher);
+ }
+ ioManager.startIO();
+
+ // 鍚姩鐩稿叧绾跨▼
+ callbackResponseDispatcher.engineThread();
+ ioManager.startIO();
+ }
+
+ // 鍒囨崲浜嗕富鏈篒P鍜岀鍙�
+ @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;
+
+ /**
+ * 鍙戦�乥ytes鏁版嵁
+ *
+ * @param bytes
+ * @return
+ */
+ private IConnectionManager sendBytes(byte[] bytes) {
+ if (ioManager == null || connectionStatus.get() != SocketStatus.SOCKET_CONNECTED) {
+ LogUtil.w("sendBytes閿欒-----ioManager涓簄ull鎴栬�卌onnectionStatus鐘舵�佷笉涓哄凡杩炴帴");
+ 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;
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/connection/connect/TcpConnection.java b/easysocket/src/main/java/com/easysocket/connection/connect/TcpConnection.java
new file mode 100644
index 0000000..c0228b7
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/connection/connect/TcpConnection.java
@@ -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锛欰lex
+ * Date锛�2019/5/29
+ * Note锛歵cp杩炴帴
+ */
+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();
+ }
+
+ /**
+ * 鏍规嵁閰嶇疆淇℃伅鑾峰彇瀵瑰簲鐨剆ocket
+ *
+ * @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;
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/connection/dispatcher/CallbackResponseDispatcher.java b/easysocket/src/main/java/com/easysocket/connection/dispatcher/CallbackResponseDispatcher.java
new file mode 100644
index 0000000..dc0d4e6
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/connection/dispatcher/CallbackResponseDispatcher.java
@@ -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锛欰lex
+ * Date锛�2019/6/4
+ * Note锛氬洖璋冩秷鎭垎鍙戝櫒
+ */
+public class CallbackResponseDispatcher {
+ /**
+ * 淇濆瓨鍙戦�佺殑姣忎釜鍥炶皟娑堟伅鐨勭洃鍚疄渚嬶紝key涓哄洖璋冩爣璇哻allbackId锛岃繖鏍峰洖璋冩秷鎭湁鍙嶉鐨勬椂鍊欙紝灏卞彲浠ユ壘鍒板苟璋冪敤
+ * 瀵瑰簲鐨勭洃鍚璞�
+ */
+ 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鍜宻hutdownNow鐨勪富瑕佸尯鍒槸鍓嶈�呬腑鏂湭鎵ц鐨勭嚎绋嬶紝鍚庤�呬腑鏂墍鏈夌嚎绋�
+ 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瀵瑰簲鐨刢allback
+ SuperCallBack callBack = callbacks.get(callbackID);
+ if (callBack != null) {
+ // 鍥炶皟
+ callBack.onSuccess(originReadData);
+ callbacks.remove(callbackID); // 绉婚櫎瀹屾垚浠诲姟鐨刢allback
+ LogUtil.d("绉婚櫎鐨刢allbackId-->" + 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));
+ }
+
+ /**
+ * 寤舵椂闃熷垪鐨刬tem
+ */
+ class timeoutItem implements Delayed {
+
+ String callbackId; // 褰撳墠callback鐨刢allbackId
+ 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鏄笉鑳戒竴鏍风殑锛屾墍浠ヨ繖閲岃鍏坈heck涓�涓嬶紝鍚﹀垯鏈嶅姟绔弽棣堢殑鏃跺�欙紝瀹㈡埛绔帴鏀跺氨浼氫贡濂�
+ *
+ * @param callbackSender
+ * @return
+ */
+ public void checkCallbackSender(SuperCallbackSender callbackSender) {
+
+ Utils.checkNotNull(socketOptions.getCallbackIDFactory(), "瑕佹兂瀹炵幇EasySocket鐨勫洖璋冨姛鑳斤紝CallbackIdFactory涓嶈兘涓簄ull锛�" +
+ "璇峰疄鐜颁竴涓狢allbackIdFactory骞跺湪鍒濆鍖栫殑鏃跺�欓�氳繃EasySocketOptions鐨剆etCallbackIdFactory杩涜閰嶇疆");
+ String callbackId = callbackSender.getCallbackId();
+ // 鍚屼竴涓秷鎭彂閫佷袱娆′互涓婏紝callbackId鏄笉鑳戒竴鏍风殑锛屽惁鍒欐湇鍔$鍙嶉鐨勬椂鍊欙紝瀹㈡埛绔帴鏀跺氨浼氫贡濂�
+ if (callbacks.containsKey(callbackId)) {
+ callbackSender.generateCallbackId();
+ }
+ }
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/connection/dispatcher/MainThreadExecutor.java b/easysocket/src/main/java/com/easysocket/connection/dispatcher/MainThreadExecutor.java
new file mode 100644
index 0000000..37e8579
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/connection/dispatcher/MainThreadExecutor.java
@@ -0,0 +1,21 @@
+package com.easysocket.connection.dispatcher;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Author锛歁apogo
+ * 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);
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/connection/dispatcher/SocketActionDispatcher.java b/easysocket/src/main/java/com/easysocket/connection/dispatcher/SocketActionDispatcher.java
new file mode 100644
index 0000000..f0a61cf
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/connection/dispatcher/SocketActionDispatcher.java
@@ -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锛欰lex
+ * Date锛�2019/6/1
+ * Note锛歴ocket琛屼负鍒嗗彂鍣�
+ */
+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();
+ /**
+ * 鍒囨崲鍒癠I绾跨▼
+ */
+ 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) {
+ // 灏嗘帴鏀跺埌鐨剆ocket琛屼负灏佽鍏ュ垪
+ 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;
+ }
+ }
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/connection/heartbeat/HeartManager.java b/easysocket/src/main/java/com/easysocket/connection/heartbeat/HeartManager.java
new file mode 100644
index 0000000..9ae8042
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/connection/heartbeat/HeartManager.java
@@ -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锛欰lex
+ * 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);
+ }
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/connection/iowork/EasyReader.java b/easysocket/src/main/java/com/easysocket/connection/iowork/EasyReader.java
new file mode 100644
index 0000000..d2bea0d
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/connection/iowork/EasyReader.java
@@ -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锛欰lex
+ * 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();
+ // 娑堟伅鍗忚涓簄ull锛屽垯鐩存帴璇诲師濮嬫秷鎭紝涓嶅缓璁繖鏍蜂娇鐢紝鍥犱负浼氬彂鐢熼粡鍖呫�佸垎鍖呯殑闂
+ if (messageProtocol == null) {
+ readOriginDataFromSteam(originalData);
+ return;
+ }
+
+ // 瀹氫箟浜嗘秷鎭崗璁�
+ int headerLength = messageProtocol.getHeaderLength(); // 鍖呭ご闀垮害
+ ByteBuffer headBuf = ByteBuffer.allocate(headerLength); // 鍖呭ご鏁版嵁鐨刡uffer
+ headBuf.order(socketOptions.getReadOrder());
+
+ /*1銆佽 header=====>>>*/
+ if (remainingBuf != null) { // 鏈変綑鐣�
+ // flip鏂规硶锛氫竴鑸粠Buffer璇绘暟鎹墠璋冪敤锛屽皢limit璁剧疆涓哄綋鍓峱osition锛屽皢position璁剧疆涓�0锛屽湪璇绘暟鎹椂锛宭imit浠h〃鍙鏁版嵁鐨勬湁鏁堥暱搴�
+ remainingBuf.flip();
+ // 璇讳綑鐣欐暟鎹殑闀垮害
+ int length = Math.min(remainingBuf.remaining(), headerLength);
+ // 璇诲叆浣欑暀鏁版嵁
+ headBuf.put(remainingBuf.array(), 0, length);
+
+ if (length < headerLength) { // 浣欑暀鏁版嵁灏忎簬涓�涓猦eader
+ // there are no data left
+ remainingBuf = null;
+ // 浠巗tream涓鍓╀笅鐨刪eader鏁版嵁
+ readHeaderFromSteam(headBuf, headerLength - length);
+ } else {
+ // 绉诲姩寮�濮嬭鏁版嵁鐨勬寚閽�
+ remainingBuf.position(headerLength);
+ }
+ } else { // 鏃犱綑鐣�
+ // 浠巗tream璇诲彇涓�涓畬鏁寸殑 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锛屽叾涓璈eader淇濆瓨娑堟伅闀垮害鍜岀被鍨嬬瓑锛孊ody淇濆瓨娑堟伅鍐呭锛岃瑙勮寖濂戒綘鐨勫崗璁�");
+ }
+ // 鍒嗛厤绌洪棿
+ ByteBuffer bodyBuf = ByteBuffer.allocate(bodyLength);
+ bodyBuf.order(socketOptions.getReadOrder());
+
+ // 鏈変綑鐣�
+ if (remainingBuf != null) {
+ int bodyStartPosition = remainingBuf.position();
+
+ int length = Math.min(remainingBuf.remaining(), bodyLength);
+ // 璇籰ength澶у皬鐨勪綑鐣欐暟鎹�
+ bodyBuf.put(remainingBuf.array(), bodyStartPosition, length);
+ // 绉诲姩position浣嶇疆
+ remainingBuf.position(bodyStartPosition + length);
+
+ // 璇荤殑浣欑暀鏁版嵁鍒氬ソ绛変簬涓�涓猙ody
+ 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鍒皁riginalData
+ 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浠h〃璇诲埌浜嗘枃浠剁殑鏈熬锛屼竴鑸槸鍥犱负鏈嶅姟鍣ㄦ柇寮�浜嗚繛鎺�
+ if (value == -1) {
+ throw new ReadRecoverableExeption("璇绘暟鎹け璐ワ紝鍙兘鏄洜涓簊ocket璺熸湇鍔″櫒鏂紑浜嗚繛鎺�");
+ }
+ 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("璇绘暟鎹け璐ワ紝鍙兘鏄洜涓簊ocket璺熸湇鍔″櫒鏂紑浜嗚繛鎺�");
+ }
+ int remaining = byteBuffer.remaining();
+ if (len > remaining) { // 浠巗tream璇荤殑鏁版嵁瓒呰繃byteBuffer鐨勫墿浣欑┖闂�
+ byteBuffer.put(bufArray, 0, remaining);
+ // 灏嗗浣欑殑鏁版嵁淇濆瓨鍒皉emainingBuf涓紦瀛橈紝绛変笅涓�娆¤鍙�
+ remainingBuf = ByteBuffer.allocate(len - remaining);
+ remainingBuf.order(socketOptions.getReadOrder());
+ remainingBuf.put(bufArray, remaining, len - remaining);
+ } else { // 浠巗tream璇荤殑鏁版嵁灏忎簬鎴栫瓑浜巄yteBuffer鐨勫墿浣欑┖闂�
+ 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();
+ }
+ }
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/connection/iowork/EasyWriter.java b/easysocket/src/main/java/com/easysocket/connection/iowork/EasyWriter.java
new file mode 100644
index 0000000..9634e16
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/connection/iowork/EasyWriter.java
@@ -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锛欰lex
+ * 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鍙戦�佹暟鎹甋tring-->" + HexUtil.bytesToHex(sendBytes));
+ LogUtil.d("EasyWriter--Socket鍙戦�佹暟鎹産yte[]-->" + 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(); // 灏唒osition浣嶇疆绉诲埌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();
+ }
+ }
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/connection/iowork/IOManager.java b/easysocket/src/main/java/com/easysocket/connection/iowork/IOManager.java
new file mode 100644
index 0000000..b1bd280
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/connection/iowork/IOManager.java
@@ -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锛欰lex
+ * 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();
+ }
+
+ // 鍒濆鍖杋o
+ 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.");
+// }
+// }
+}
diff --git a/easysocket/src/main/java/com/easysocket/connection/reconnect/AbsReconnection.java b/easysocket/src/main/java/com/easysocket/connection/reconnect/AbsReconnection.java
new file mode 100644
index 0000000..81e77ff
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/connection/reconnect/AbsReconnection.java
@@ -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锛欰lex
+ * 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
+ }
+
+ /**
+ * 鏄惁姝e湪閲嶈繛
+ * @return
+ */
+ public abstract boolean isReconning();
+}
diff --git a/easysocket/src/main/java/com/easysocket/connection/reconnect/DefaultReConnection.java b/easysocket/src/main/java/com/easysocket/connection/reconnect/DefaultReConnection.java
new file mode 100644
index 0000000..959563d
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/connection/reconnect/DefaultReConnection.java
@@ -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锛欰lex
+ * Date锛�2019/5/28
+ * Note锛氶粯璁ら噸杩炲櫒
+ */
+public class DefaultReConnection extends AbsReconnection {
+ /**
+ * 鏈�澶ц繛鎺ュけ璐ユ鏁帮紝瓒呰繃鍙互鍒囨崲鍒板鐢ㄧ殑鏈嶅姟鍣ㄥ湴鍧�
+ */
+ private static final int MAX_CONNECTION_FAILED_TIMES = 10;
+ /**
+ * 杩炴帴澶辫触鐨勬鏁�
+ */
+ private int connectionFailedTimes = 0;
+ /**
+ * 閲嶈繛闂撮殧涓嶈兘灏忎簬10绉掞紝涓轰簡閬垮厤鍏ㄩ儴瀹㈡埛绔痵ocket鍦ㄥ悓涓�鏃堕棿杩炴帴鏈嶅姟绔紝闂撮殧鏃堕棿闇�瑕佷笂涓嬫诞鍔�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绫诲瀷鐨勫璞★紝姣旇緝瀹冧滑鐨勭被鍨嬪璞℃槸鍚�==锛屽叾瀹炴槸姣旇緝瀹冧滑鏄惁涓哄悓涓�涓狢lass鍒涘缓鐨勫璞�
+ 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,鍒欒疆娴佸垏鎹袱涓猦ost
+ 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();
+ }
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/entity/OriginReadData.java b/easysocket/src/main/java/com/easysocket/entity/OriginReadData.java
new file mode 100644
index 0000000..da184c6
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/entity/OriginReadData.java
@@ -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锛欰lex
+ * 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鐨剆tring
+ *
+ * @return
+ */
+ public String getBodyString() {
+ return new String(getBodyBytes(), Charset.forName(EasySocket.getInstance().getDefOptions().getCharsetName()));
+ }
+
+ /**
+ * 鑾峰彇瀹屾暣鐨勬暟鎹紝鍖呮嫭鍖呭ご鍜屽寘浣�
+ *
+ * @return
+ */
+ public byte[] getOriginDataBytes() {
+ return Utils.concatBytes(getHeaderData(), getBodyBytes());
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/entity/SocketAddress.java b/easysocket/src/main/java/com/easysocket/entity/SocketAddress.java
new file mode 100644
index 0000000..a4187eb
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/entity/SocketAddress.java
@@ -0,0 +1,54 @@
+package com.easysocket.entity;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/5/31
+ * Note锛歴ocket涓绘満鍦板潃
+ */
+public class SocketAddress {
+
+ /**
+ * IPV4鍦板潃
+ */
+ private String ip;
+ /**
+ * 杩炴帴鏈嶅姟鍣ㄧ鍙e彿
+ */
+ private int port;
+ /**
+ * 褰撴IP鍦板潃Ping涓嶉�氭椂鐨勫鐢↖P
+ */
+ private SocketAddress backupAddress;
+
+ /**
+ * 鑾峰彇澶囩敤鐨処p鍜岀鍙e彿
+ *
+ * @return 澶囩敤鐨勭鍙e彿鍜孖P鍦板潃
+ */
+ public SocketAddress getBackupAddress() {
+ return backupAddress;
+ }
+
+ /**
+ * 璁剧疆澶囩敤鐨処P鍜岀鍙e彿,鍙互涓嶈缃�
+ *
+ * @param backupAddress 澶囩敤鐨処P鍜岀鍙e彿淇℃伅
+ */
+ 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;
+ }
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/entity/basemsg/IResponse.java b/easysocket/src/main/java/com/easysocket/entity/basemsg/IResponse.java
new file mode 100644
index 0000000..9e08c7c
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/entity/basemsg/IResponse.java
@@ -0,0 +1,9 @@
+package com.easysocket.entity.basemsg;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/12/8
+ * Note锛�
+ */
+public interface IResponse {
+}
diff --git a/easysocket/src/main/java/com/easysocket/entity/basemsg/ISender.java b/easysocket/src/main/java/com/easysocket/entity/basemsg/ISender.java
new file mode 100644
index 0000000..4f34083
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/entity/basemsg/ISender.java
@@ -0,0 +1,11 @@
+package com.easysocket.entity.basemsg;
+
+import java.io.Serializable;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/1
+ * Note锛氬彂閫佹暟鎹殑鎺ュ彛
+ */
+public interface ISender extends Serializable {
+}
diff --git a/easysocket/src/main/java/com/easysocket/entity/basemsg/SuperCallbackResponse.java b/easysocket/src/main/java/com/easysocket/entity/basemsg/SuperCallbackResponse.java
new file mode 100644
index 0000000..7bdb330
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/entity/basemsg/SuperCallbackResponse.java
@@ -0,0 +1,13 @@
+package com.easysocket.entity.basemsg;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/12/7
+ */
+public abstract class SuperCallbackResponse implements IResponse {
+
+ public abstract String getCallbackId();
+
+ public abstract void setCallbackId(String callbackId);
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/entity/basemsg/SuperCallbackSender.java b/easysocket/src/main/java/com/easysocket/entity/basemsg/SuperCallbackSender.java
new file mode 100644
index 0000000..2f1480d
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/entity/basemsg/SuperCallbackSender.java
@@ -0,0 +1,36 @@
+package com.easysocket.entity.basemsg;
+
+import com.easysocket.utils.Utils;
+
+/**
+ * Author锛欰lex
+ * 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锛屽湪娑堟伅鍙戦�佸墠鎵ц锛孋allbackId浣滀负娑堟伅鐨勫敮涓�鏍囪瘑涓�璧蜂紶缁欐湇鍔″櫒锛屾湇鍔″櫒鍙嶉
+ * 褰撳墠娑堟伅鐨勬椂鍊欎篃鏄惡甯﹀悓鏍风殑CallbackId缁欏鎴风锛岀敤浠ヨ瘑鍒�
+ */
+ public void generateCallbackId() {
+ callbackId= Utils.getRandomChar(20);
+ }
+}
+
diff --git a/easysocket/src/main/java/com/easysocket/entity/basemsg/SuperSender.java b/easysocket/src/main/java/com/easysocket/entity/basemsg/SuperSender.java
new file mode 100644
index 0000000..e700263
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/entity/basemsg/SuperSender.java
@@ -0,0 +1,9 @@
+package com.easysocket.entity.basemsg;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/10/19
+ * Note锛氬熀纭�娑堟伅
+ */
+public class SuperSender implements ISender {
+}
diff --git a/easysocket/src/main/java/com/easysocket/exception/InitialExeption.java b/easysocket/src/main/java/com/easysocket/exception/InitialExeption.java
new file mode 100644
index 0000000..772306d
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/exception/InitialExeption.java
@@ -0,0 +1,12 @@
+package com.easysocket.exception;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/5
+ * Note锛氬垵濮嬪寲寮傚父
+ */
+public class InitialExeption extends RuntimeException{
+ public InitialExeption(String s){
+ super(s);
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/exception/NotNullException.java b/easysocket/src/main/java/com/easysocket/exception/NotNullException.java
new file mode 100644
index 0000000..dc5092e
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/exception/NotNullException.java
@@ -0,0 +1,12 @@
+package com.easysocket.exception;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/5
+ * Note锛氶潪绌哄紓甯�
+ */
+public class NotNullException extends RuntimeException {
+ public NotNullException(String e) {
+ super(e);
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/exception/ReadRecoverableExeption.java b/easysocket/src/main/java/com/easysocket/exception/ReadRecoverableExeption.java
new file mode 100644
index 0000000..ad70ee2
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/exception/ReadRecoverableExeption.java
@@ -0,0 +1,13 @@
+package com.easysocket.exception;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/5
+ * Note锛氬彲鎭㈠socket璇绘暟鎹紓甯�
+ */
+public class ReadRecoverableExeption extends Exception {
+
+ public ReadRecoverableExeption(String s){
+ super(s);
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/exception/ReadUnrecoverableException.java b/easysocket/src/main/java/com/easysocket/exception/ReadUnrecoverableException.java
new file mode 100644
index 0000000..26c1956
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/exception/ReadUnrecoverableException.java
@@ -0,0 +1,12 @@
+package com.easysocket.exception;
+
+/**
+ * Author锛歁apogo
+ * Date锛�2020/12/29
+ * Note锛氫笉鍙慨澶嶇殑璇诲彇閿欒
+ */
+public class ReadUnrecoverableException extends Exception {
+ public ReadUnrecoverableException(String s) {
+ super(s);
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/exception/RequestCancelException.java b/easysocket/src/main/java/com/easysocket/exception/RequestCancelException.java
new file mode 100644
index 0000000..f899342
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/exception/RequestCancelException.java
@@ -0,0 +1,13 @@
+package com.easysocket.exception;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/4
+ * Note锛氳姹傚彇娑堝紓甯�
+ */
+public class RequestCancelException extends Exception{
+
+ public RequestCancelException(String s){
+ super(s);
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/exception/RequestTimeOutException.java b/easysocket/src/main/java/com/easysocket/exception/RequestTimeOutException.java
new file mode 100644
index 0000000..51768ae
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/exception/RequestTimeOutException.java
@@ -0,0 +1,13 @@
+package com.easysocket.exception;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/4
+ * Note锛氳姹傝秴鏃跺紓甯�
+ */
+public class RequestTimeOutException extends Exception{
+
+ public RequestTimeOutException(String s){
+ super(s);
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/callback/ICallBack.java b/easysocket/src/main/java/com/easysocket/interfaces/callback/ICallBack.java
new file mode 100644
index 0000000..5c48e23
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/callback/ICallBack.java
@@ -0,0 +1,18 @@
+package com.easysocket.interfaces.callback;
+
+import com.easysocket.callback.SuperCallBack;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/5
+ * Note锛�
+ */
+public interface ICallBack {
+ /**
+ * socket璇锋眰鍥炶皟
+ * @param callBack
+ */
+ void onCallBack(SuperCallBack callBack);
+
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/callback/IProgressDialog.java b/easysocket/src/main/java/com/easysocket/interfaces/callback/IProgressDialog.java
new file mode 100644
index 0000000..3e66dae
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/callback/IProgressDialog.java
@@ -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();
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/callback/IType.java b/easysocket/src/main/java/com/easysocket/interfaces/callback/IType.java
new file mode 100644
index 0000000..4193247
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/callback/IType.java
@@ -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();
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/callback/ProgressCancelListener.java b/easysocket/src/main/java/com/easysocket/interfaces/callback/ProgressCancelListener.java
new file mode 100644
index 0000000..c64e9f5
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/callback/ProgressCancelListener.java
@@ -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();
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/config/IConnectionSwitchListener.java b/easysocket/src/main/java/com/easysocket/interfaces/config/IConnectionSwitchListener.java
new file mode 100644
index 0000000..1260c5d
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/config/IConnectionSwitchListener.java
@@ -0,0 +1,13 @@
+package com.easysocket.interfaces.config;
+
+import com.easysocket.entity.SocketAddress;
+import com.easysocket.interfaces.conn.IConnectionManager;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/4
+ * Note锛�
+ */
+public interface IConnectionSwitchListener {
+ void onSwitchConnectionInfo(IConnectionManager manager, SocketAddress oldAddress, SocketAddress newAddress);
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/config/IMessageProtocol.java b/easysocket/src/main/java/com/easysocket/interfaces/config/IMessageProtocol.java
new file mode 100644
index 0000000..0808511
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/config/IMessageProtocol.java
@@ -0,0 +1,20 @@
+package com.easysocket.interfaces.config;
+
+import java.nio.ByteOrder;
+
+/**
+ * 娑堟伅鏁版嵁鏍煎紡
+ */
+public interface IMessageProtocol {
+
+ /**
+ * 鑾峰彇鍖呭ご鐨勯暱搴�
+ */
+ int getHeaderLength();
+
+ /**
+ * 鑾峰彇鏁版嵁鍖呬綋鐨勯暱搴︼紝鏍规嵁鍗忚杩欎釜闀垮害搴旇鍐欏湪鍖呭ご涓紝鍦ㄨ鍙栨暟鎹椂鐢ㄥ埌
+ */
+ int getBodyLength(byte[] header, ByteOrder byteOrder);
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/config/IOptions.java b/easysocket/src/main/java/com/easysocket/interfaces/config/IOptions.java
new file mode 100644
index 0000000..f732839
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/config/IOptions.java
@@ -0,0 +1,22 @@
+package com.easysocket.interfaces.config;
+
+import com.easysocket.config.EasySocketOptions;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/1
+ * Note锛�
+ */
+public interface IOptions<T> {
+ /**
+ * 璁剧疆閰嶇疆淇℃伅
+ * @param socketOptions
+ */
+ T setOptions(EasySocketOptions socketOptions);
+
+ /**
+ * 鑾峰彇閰嶇疆淇℃伅
+ * @return
+ */
+ EasySocketOptions getOptions();
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/conn/IConnectionManager.java b/easysocket/src/main/java/com/easysocket/interfaces/conn/IConnectionManager.java
new file mode 100644
index 0000000..94d88ed
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/conn/IConnectionManager.java
@@ -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锛欰lex
+ * 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();
+
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/conn/IHeartManager.java b/easysocket/src/main/java/com/easysocket/interfaces/conn/IHeartManager.java
new file mode 100644
index 0000000..5bbad47
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/conn/IHeartManager.java
@@ -0,0 +1,28 @@
+package com.easysocket.interfaces.conn;
+
+import com.easysocket.connection.heartbeat.HeartManager;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/12/8
+ * Note锛�
+ */
+public interface IHeartManager {
+
+ /**
+ * 寮�濮嬪績璺�
+ * @param clientHeart
+ */
+ void startHeartbeat(byte[] clientHeart, HeartManager.HeartbeatListener listener);
+
+ /**
+ * 鍋滄蹇冭烦
+ */
+ void stopHeartbeat();
+
+
+ /**
+ * 鎺ユ敹鍒板績璺�
+ */
+ void onReceiveHeartBeat();
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/conn/IReconnListener.java b/easysocket/src/main/java/com/easysocket/interfaces/conn/IReconnListener.java
new file mode 100644
index 0000000..ed48ac1
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/conn/IReconnListener.java
@@ -0,0 +1,20 @@
+package com.easysocket.interfaces.conn;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/1
+ * Note锛�
+ */
+public interface IReconnListener {
+
+ /**
+ * 鍏宠仈杩炴帴鍣�
+ * @param iConnectionManager
+ */
+ void attach(IConnectionManager iConnectionManager);
+
+ /**
+ * 鍒嗙杩炴帴鍣�
+ */
+ void detach();
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/conn/ISend.java b/easysocket/src/main/java/com/easysocket/interfaces/conn/ISend.java
new file mode 100644
index 0000000..c9cd772
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/conn/ISend.java
@@ -0,0 +1,25 @@
+package com.easysocket.interfaces.conn;
+
+import com.easysocket.entity.basemsg.SuperCallbackSender;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/5
+ * Note锛氬彂閫佹帴鍙�
+ */
+public interface ISend {
+
+ /**
+ * 鍙戦�佷竴涓湁鍥炶皟鐨勬秷鎭�
+ * @param sender
+ * @return
+ */
+ IConnectionManager upCallbackMessage(SuperCallbackSender sender);
+
+ /**
+ * 鍙戦�乥ytes
+ * @param bytes
+ * @return
+ */
+ IConnectionManager upBytes(byte[] bytes);
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/conn/ISocketActionDispatch.java b/easysocket/src/main/java/com/easysocket/interfaces/conn/ISocketActionDispatch.java
new file mode 100644
index 0000000..c028978
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/conn/ISocketActionDispatch.java
@@ -0,0 +1,38 @@
+package com.easysocket.interfaces.conn;
+
+import java.io.Serializable;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/1
+ * Note锛歴ocket琛屼负鍒嗗彂鎺ュ彛
+ */
+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);
+
+ /**
+ * 瑙i櫎socket琛屼负鐨勮闃�
+ * @param iSocketActionListener
+ */
+ void unsubscribe(ISocketActionListener iSocketActionListener);
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/conn/ISocketActionListener.java b/easysocket/src/main/java/com/easysocket/interfaces/conn/ISocketActionListener.java
new file mode 100644
index 0000000..82ecb60
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/conn/ISocketActionListener.java
@@ -0,0 +1,52 @@
+package com.easysocket.interfaces.conn;
+
+import com.easysocket.entity.OriginReadData;
+import com.easysocket.entity.SocketAddress;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/1
+ * Note锛歴ocket琛屼负鐩戝惉鎺ュ彛
+ */
+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);
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/conn/ISubscribeSocketAction.java b/easysocket/src/main/java/com/easysocket/interfaces/conn/ISubscribeSocketAction.java
new file mode 100644
index 0000000..27fc89e
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/conn/ISubscribeSocketAction.java
@@ -0,0 +1,20 @@
+package com.easysocket.interfaces.conn;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/1
+ * Note锛氳闃呯洃鍚瑂ocket
+ */
+public interface ISubscribeSocketAction {
+ /**
+ * 娉ㄥ唽鐩戝惉socket鐨勮涓�
+ * @param iSocketActionListener
+ */
+ void subscribeSocketAction(ISocketActionListener iSocketActionListener);
+
+ /**
+ * 娉ㄩ攢鐩戝惉socket鐨勮涓�
+ * @param iSocketActionListener
+ */
+ void unSubscribeSocketAction(ISocketActionListener iSocketActionListener);
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/conn/SocketActionListener.java b/easysocket/src/main/java/com/easysocket/interfaces/conn/SocketActionListener.java
new file mode 100644
index 0000000..a63a874
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/conn/SocketActionListener.java
@@ -0,0 +1,57 @@
+package com.easysocket.interfaces.conn;
+
+import com.easysocket.entity.OriginReadData;
+import com.easysocket.entity.SocketAddress;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/4
+ * Note锛歴ocket琛屼负鐩戝惉鐨勬娊璞$被锛岀户鎵挎绫诲彲浠ラ�夋嫨鎬у湴閲嶅啓鏂规硶
+ */
+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) {
+
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/io/IIOManager.java b/easysocket/src/main/java/com/easysocket/interfaces/io/IIOManager.java
new file mode 100644
index 0000000..3cdf538
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/io/IIOManager.java
@@ -0,0 +1,27 @@
+package com.easysocket.interfaces.io;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/1
+ * Note锛�
+ */
+public interface IIOManager {
+
+ /**
+ * 鍙戦�佸瓧鑺傛祦
+ *
+ * @param bytes
+ */
+ void sendBytes(byte[] bytes);
+
+ /**
+ * 鍏抽棴io绠$悊鍣�
+ */
+ void closeIO();
+
+ /**
+ * 寮�鍚痠o鎿嶄綔
+ */
+ void startIO();
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/io/IReader.java b/easysocket/src/main/java/com/easysocket/interfaces/io/IReader.java
new file mode 100644
index 0000000..3104c06
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/io/IReader.java
@@ -0,0 +1,32 @@
+package com.easysocket.interfaces.io;
+
+/**
+ * Author锛欰lex
+ * Date锛�2019/6/1
+ * Note锛�
+ */
+public interface IReader<T> {
+
+ /**
+ * 璇绘暟鎹�
+ */
+ void read() throws Exception;
+
+ /**
+ * 鎵撳紑鏁版嵁鐨勮鍙�
+ */
+ void openReader();
+
+ /**
+ * 鍏抽棴鏁版嵁鐨勮鍙�
+ */
+ void closeReader();
+
+ /**
+ * 璁剧疆鍙傛暟
+ * @param t
+ */
+ void setOption(T t);
+
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/interfaces/io/IWriter.java b/easysocket/src/main/java/com/easysocket/interfaces/io/IWriter.java
new file mode 100644
index 0000000..644e7f5
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/interfaces/io/IWriter.java
@@ -0,0 +1,38 @@
+package com.easysocket.interfaces.io;
+
+import java.io.IOException;
+
+/**
+ * Author锛欰lex
+ * 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);
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/utils/HexUtil.java b/easysocket/src/main/java/com/easysocket/utils/HexUtil.java
new file mode 100644
index 0000000..a92049b
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/utils/HexUtil.java
@@ -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;
+ }
+}
diff --git a/easysocket/src/main/java/com/easysocket/utils/LogUtil.java b/easysocket/src/main/java/com/easysocket/utils/LogUtil.java
new file mode 100644
index 0000000..df549bf
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/utils/LogUtil.java
@@ -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);
+ }
+
+}
diff --git a/easysocket/src/main/java/com/easysocket/utils/Utils.java b/easysocket/src/main/java/com/easysocket/utils/Utils.java
new file mode 100644
index 0000000..10d97c5
--- /dev/null
+++ b/easysocket/src/main/java/com/easysocket/utils/Utils.java
@@ -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(); //杩斿洖鐩存帴缁ф壙鐨勭埗绫伙紙鍖呭惈娉涘瀷鍙傛暟锛夌被鍨�,濡傛灉鏈夋硾鍨婽,涔熻鍖呮嫭杩涘幓
+ //getActualTypeArguments 鑾峰彇娉涘瀷涓殑瀹為檯绫诲瀷锛屾瘮濡侻ap<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;
+ }
+ //濡傛灉娉涘瀷绫诲瀷杩樻槸鍙橀噺绫诲瀷锛屾瘮濡俆銆乂涔嬬被鐨勶紝浠h〃娌℃湁濉啓娉涘瀷鍙傛暟
+ 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 鏄惁涓轰富绾跨▼鐨刪andler锛屼负false鏃惰繑鍥炵殑鏄綋鍓嶇嚎绋媓andler
+ * @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;
+ }
+
+}
diff --git a/settings.gradle b/settings.gradle
index 6abf7c7..a91ce91 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -15,4 +15,4 @@
}
}
rootProject.name = "chargeQh"
-include ':app',':pickerviewlibrary'
+include ':app',':pickerviewlibrary',':easysocket'
--
Gitblit v1.8.0