From dce8fc9c184fb7fec64aaefa11a3be627a54093b Mon Sep 17 00:00:00 2001
From: endian11 <Dana_Lee1016@126.com>
Date: 星期四, 12 十二月 2019 15:54:19 +0800
Subject: [PATCH] 测试升级学员表(学员表增加一列);增加im_lib(tcp连接)

---
 im_lib/src/main/AndroidManifest.xml                                           |    2 
 im_lib/src/main/java/com/anyun/im_lib/MsgTimeOutTimerManager.java             |   33 +
 im_lib/src/main/java/com/anyun/im_lib/netty/TCPChannelInitializerHandler.java |   64 ++
 app/src/main/java/safeluck/drive/evaluation/fragment/TrainFragment.java       |    2 
 im_lib/src/main/java/com/anyun/im_lib/interf/IMSClientInteface.java           |  114 ++++
 im_lib/libs/netty-all-4.1.43.jar                                              |    0 
 im_lib/src/main/java/com/anyun/im_lib/HeartbeatRespHandler.java               |   22 
 im_lib/src/main/java/com/anyun/im_lib/netty/NettyTcpClient.java               |  497 +++++++++++++++++++++
 im_lib/build.gradle                                                           |   34 +
 im_lib/src/main/java/com/anyun/im_lib/ExecutorServiceFactory.java             |  100 ++++
 app/build.gradle                                                              |    1 
 im_lib/src/main/java/com/anyun/im_lib/listener/IMSConnectStatusCallback.java  |   20 
 settings.gradle                                                               |    2 
 im_lib/src/androidTest/java/com/anyun/im_lib/ExampleInstrumentedTest.java     |   27 +
 im_lib/src/main/java/com/anyun/im_lib/MsgTimeoutTimer.java                    |   36 +
 im_lib/src/test/java/com/anyun/im_lib/ExampleUnitTest.java                    |   17 
 im_lib/src/main/java/com/anyun/im_lib/IMSClientFactory.java                   |   16 
 im_lib/src/main/java/com/anyun/im_lib/listener/OnEventListener.java           |   60 ++
 im_lib/src/main/java/com/anyun/im_lib/HeartbeatHandler.java                   |   12 
 im_lib/src/main/java/com/anyun/im_lib/im/IMSClientBootstrap.java              |   61 ++
 im_lib/proguard-rules.pro                                                     |   21 
 im_lib/src/main/java/com/anyun/im_lib/LoginAuthRespHandler.java               |   42 +
 im_lib/src/main/res/values/strings.xml                                        |    3 
 im_lib/src/main/java/com/anyun/im_lib/IMSConfig.java                          |   29 +
 im_lib/src/main/java/com/anyun/im_lib/MsgDispatcher.java                      |   25 +
 app/src/main/java/safeluck/drive/evaluation/DB/WorkRoomDataBase.java          |   12 
 im_lib/src/main/java/com/anyun/im_lib/netty/TCPReadHandler.java               |   66 ++
 app/src/main/java/safeluck/drive/evaluation/DB/Student.java                   |   10 
 28 files changed, 1,325 insertions(+), 3 deletions(-)

diff --git a/app/build.gradle b/app/build.gradle
index 534a8e5..65e4132 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -55,4 +55,5 @@
     implementation project(path: ':lib')
     implementation 'com.google.code.gson:gson:2.8.6'
     implementation 'com.facebook.stetho:stetho:1.5.0'
+    implementation project(path: ':im_lib')
 }
diff --git a/app/src/main/java/safeluck/drive/evaluation/DB/Student.java b/app/src/main/java/safeluck/drive/evaluation/DB/Student.java
index 7bdd242..f44e818 100644
--- a/app/src/main/java/safeluck/drive/evaluation/DB/Student.java
+++ b/app/src/main/java/safeluck/drive/evaluation/DB/Student.java
@@ -30,6 +30,16 @@
     @ColumnInfo(name = "sex")
     private int sex;
 
+    public long getBegin_time() {
+        return begin_time;
+    }
+
+    public void setBegin_time(long begin_time) {
+        this.begin_time = begin_time;
+    }
+
+    private long begin_time;
+
     public Student(long stu_id, @NonNull String name, String ID, int sex) {
         this.stu_id = stu_id;
         this.name = name;
diff --git a/app/src/main/java/safeluck/drive/evaluation/DB/WorkRoomDataBase.java b/app/src/main/java/safeluck/drive/evaluation/DB/WorkRoomDataBase.java
index 97aff86..5c0fd1f 100644
--- a/app/src/main/java/safeluck/drive/evaluation/DB/WorkRoomDataBase.java
+++ b/app/src/main/java/safeluck/drive/evaluation/DB/WorkRoomDataBase.java
@@ -7,6 +7,7 @@
 import androidx.room.Database;
 import androidx.room.Room;
 import androidx.room.RoomDatabase;
+import androidx.room.migration.Migration;
 import androidx.sqlite.db.SupportSQLiteDatabase;
 import androidx.work.OneTimeWorkRequest;
 import androidx.work.WorkManager;
@@ -31,7 +32,7 @@
  * 閭锛�632393724@qq.com
  * All Rights Saved! Chongqing AnYun Tech co. LTD
  */
-@Database(entities = {Student.class, CriteriaForI.class, FailedProj.class, CriteriaForII.class},version = 1,exportSchema = false)
+@Database(entities = {Student.class, CriteriaForI.class, FailedProj.class, CriteriaForII.class},version = 2,exportSchema = false)
 public abstract class WorkRoomDataBase extends RoomDatabase {
     private static final String TAG = "WorkRoomDataBase";
     public abstract StudentDao getstudentDao();
@@ -46,6 +47,14 @@
     private static final int NUMBER_OF_THREADS = 4;
 
     public static final ExecutorService dataBaseWriteExecutor = Executors.newFixedThreadPool(NUMBER_OF_THREADS);
+    static Migration migration = new Migration(1,2) {
+        @Override
+        public void migrate(@NonNull SupportSQLiteDatabase database) {
+            database.execSQL("alter table student_table ADD  COLUMN begin_time INTEGER NOT NULL DEFAULT 0");
+        }
+    };
+private static final Migration[] ALL_MIGRATIONS = new Migration[]{migration};
+
 
      public static WorkRoomDataBase getWorkRoomDataBase(final Context mContext){
          Log.i(TAG, "getWorkRoomDataBase");
@@ -54,6 +63,7 @@
                 if (workRoomDataBase == null){
                     Log.i(TAG, "getWorkRoomDataBase==null ");
                     workRoomDataBase = Room.databaseBuilder(mContext.getApplicationContext(),WorkRoomDataBase.class,"work_database")
+                            .addMigrations(ALL_MIGRATIONS)
                             .addCallback(new Callback() {
                                 @Override
                                 public void onCreate(@NonNull SupportSQLiteDatabase db) {
diff --git a/app/src/main/java/safeluck/drive/evaluation/fragment/TrainFragment.java b/app/src/main/java/safeluck/drive/evaluation/fragment/TrainFragment.java
index 0ace87a..d2a793d 100644
--- a/app/src/main/java/safeluck/drive/evaluation/fragment/TrainFragment.java
+++ b/app/src/main/java/safeluck/drive/evaluation/fragment/TrainFragment.java
@@ -67,7 +67,7 @@
 
 
         FailedProjViewModel failedProjViewModel =ViewModelProviders.of(this).get(FailedProjViewModel.class);
-        failedProjViewModel.getFailedProjectsForI(1000).observe(this, new Observer<List<FailedProj_select>>() {
+        failedProjViewModel.getFailedProjectsForI(1001).observe(this, new Observer<List<FailedProj_select>>() {
             @Override
             public void onChanged(List<FailedProj_select> failedProj_selects) {
                 item_id = 0;
diff --git a/im_lib/build.gradle b/im_lib/build.gradle
new file mode 100644
index 0000000..8ac8395
--- /dev/null
+++ b/im_lib/build.gradle
@@ -0,0 +1,34 @@
+apply plugin: 'com.android.library'
+
+android {
+    compileSdkVersion 29
+
+
+    defaultConfig {
+        minSdkVersion 21
+        targetSdkVersion 29
+        versionCode 1
+        versionName "1.0"
+
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+        consumerProguardFiles 'consumer-rules.pro'
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+
+}
+
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+
+    implementation 'androidx.appcompat:appcompat:1.0.2'
+    testImplementation 'junit:junit:4.12'
+    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+    implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
+}
diff --git a/im_lib/libs/netty-all-4.1.43.jar b/im_lib/libs/netty-all-4.1.43.jar
new file mode 100644
index 0000000..a0b8316
--- /dev/null
+++ b/im_lib/libs/netty-all-4.1.43.jar
Binary files differ
diff --git a/im_lib/proguard-rules.pro b/im_lib/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/im_lib/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/im_lib/src/androidTest/java/com/anyun/im_lib/ExampleInstrumentedTest.java b/im_lib/src/androidTest/java/com/anyun/im_lib/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..e58f22a
--- /dev/null
+++ b/im_lib/src/androidTest/java/com/anyun/im_lib/ExampleInstrumentedTest.java
@@ -0,0 +1,27 @@
+package com.anyun.im_lib;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+    @Test
+    public void useAppContext() {
+        // Context of the app under test.
+        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+        assertEquals("com.anyun.im_lib.test", appContext.getPackageName());
+    }
+}
diff --git a/im_lib/src/main/AndroidManifest.xml b/im_lib/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a7663f8
--- /dev/null
+++ b/im_lib/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.anyun.im_lib" />
diff --git a/im_lib/src/main/java/com/anyun/im_lib/ExecutorServiceFactory.java b/im_lib/src/main/java/com/anyun/im_lib/ExecutorServiceFactory.java
new file mode 100644
index 0000000..410c052
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/ExecutorServiceFactory.java
@@ -0,0 +1,100 @@
+package com.anyun.im_lib;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * MyApplication2
+ * Created by lzw on 2019/12/2. 14:15:59
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public class ExecutorServiceFactory {
+
+    /*** 绠$悊绾跨▼缁勶紝璐熻矗閲嶈繛***/
+    private ExecutorService bossPool;
+    /*** 宸ヤ綔绾跨▼缁勶紝璐熻矗蹇冭烦***/
+    private ExecutorService workPool;
+
+    /**
+     * 鍒濆鍖朆oss绾跨▼姹�
+     */
+    public synchronized void initBossLoopGroup(){
+        initBossLoopGroup(1);
+    }
+
+    /**
+     * 鍒濆鍖杦ork绾跨▼姹�
+     */
+    public synchronized void initWorkLoopGroup(){
+        initWorkLoopGroup(1);
+    }
+
+    /**
+     * 鎵цBoss浠诲姟
+     * @param runnable
+     */
+    public void  execBossTask(Runnable runnable){
+        if (bossPool == null){
+            initBossLoopGroup();
+        }
+        bossPool.execute(runnable);
+    }
+    /**
+     * 鎵цwork浠诲姟
+     * @param runnable
+     */
+    public void  execWorkTask(Runnable runnable){
+        if (workPool == null){
+            initWorkLoopGroup();
+        }
+        workPool.execute(runnable);
+    }
+
+    private void initWorkLoopGroup(int size) {
+        destroyWorkLoopGroup();
+        workPool = Executors.newFixedThreadPool(size);
+    }
+
+    private void initBossLoopGroup(int size) {
+        destroyBossLoopGroup();
+        bossPool = Executors.newFixedThreadPool(size);
+    }
+
+    /**
+     * 閲婃斁boss绾跨▼姹�
+     */
+    private void destroyBossLoopGroup() {
+        if (bossPool != null){
+            try {
+                bossPool.shutdownNow();
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                bossPool = null;
+            }
+        }
+    }
+ /**
+     * 閲婃斁work绾跨▼姹�
+     */
+ public void destroyWorkLoopGroup() {
+        if (workPool != null){
+            try {
+                workPool.shutdownNow();
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                workPool = null;
+            }
+        }
+    }
+
+    /**
+     * 閲婃斁鎵�鏈夌嚎绋�
+     */
+    public void destroy() {
+        destroyBossLoopGroup();
+        destroyWorkLoopGroup();
+    }
+}
diff --git a/im_lib/src/main/java/com/anyun/im_lib/HeartbeatHandler.java b/im_lib/src/main/java/com/anyun/im_lib/HeartbeatHandler.java
new file mode 100644
index 0000000..a0e4314
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/HeartbeatHandler.java
@@ -0,0 +1,12 @@
+package com.anyun.im_lib;
+
+import io.netty.channel.ChannelInboundHandlerAdapter;
+
+/**
+ * MyApplication2
+ * Created by lzw on 2019/12/4. 11:31:25
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public class HeartbeatHandler extends ChannelInboundHandlerAdapter  {
+}
diff --git a/im_lib/src/main/java/com/anyun/im_lib/HeartbeatRespHandler.java b/im_lib/src/main/java/com/anyun/im_lib/HeartbeatRespHandler.java
new file mode 100644
index 0000000..ba1c8bf
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/HeartbeatRespHandler.java
@@ -0,0 +1,22 @@
+package com.anyun.im_lib;
+
+import com.anyun.im_lib.interf.IMSClientInteface;
+
+import io.netty.channel.ChannelInboundHandlerAdapter;
+
+/**
+ * MyApplication2
+ * Created by lzw on 2019/12/4. 11:50:05
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public class HeartbeatRespHandler extends ChannelInboundHandlerAdapter {
+
+    private static final String TAG = HeartbeatRespHandler.class.getSimpleName();
+
+    private IMSClientInteface imsClient;
+
+    public HeartbeatRespHandler(IMSClientInteface imsClient) {
+        this.imsClient = imsClient;
+    }
+}
diff --git a/im_lib/src/main/java/com/anyun/im_lib/IMSClientFactory.java b/im_lib/src/main/java/com/anyun/im_lib/IMSClientFactory.java
new file mode 100644
index 0000000..d3f69dc
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/IMSClientFactory.java
@@ -0,0 +1,16 @@
+package com.anyun.im_lib;
+
+import com.anyun.im_lib.interf.IMSClientInteface;
+import com.anyun.im_lib.netty.NettyTcpClient;
+
+/**
+ * MyApplication2
+ * Created by lzw on 2019/12/2. 13:13:44
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public class IMSClientFactory {
+    public static IMSClientInteface getIMSClient() {
+        return NettyTcpClient.getInstance();
+    }
+}
diff --git a/im_lib/src/main/java/com/anyun/im_lib/IMSConfig.java b/im_lib/src/main/java/com/anyun/im_lib/IMSConfig.java
new file mode 100644
index 0000000..646ad15
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/IMSConfig.java
@@ -0,0 +1,29 @@
+package com.anyun.im_lib;
+
+/**
+ * MyApplication2
+ * Created by lzw on 2019/12/2. 14:16:22
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public class IMSConfig {
+    public static final int CONNECT_STATE_FAILURE = -1;
+    public static final int DEFAULT_RECONNECT_BASE_DELAY_TIME = 3 * 1000;
+    public static final int DEFAULT_CONNECT_TIMEOUT = 10 * 1000;
+    public static final int DEFAULT_HEARTBEAT_INTERVAL_FOREGROUND = 3 * 1000;
+    public static final int DEFAULT_HEARTBEAT_INTERVAL_BACKGROUND = 30 * 1000;
+
+    /*** 搴旂敤鍦ㄥ墠鍙版爣璇�***/
+    public static final int APP_STATUS_FOREGROUND = 0;
+    /*** 搴旂敤鍦ㄥ悗鍙版爣璇�***/
+    public static final int APP_STATUS_BACKGROUND = -1;
+    /*** 榛樿娑堟伅鍙戦�佸け璐ラ噸鍙戞鏁� ***/
+    public static final int DEFAULT_RESEND_COUNT = 3;
+    public static final int DEFAULT_RESEND_INTERVAL = 8 * 1000;
+
+    /******榛樿閲嶈繛涓�涓懆鏈熷け璐ラ棿闅旀椂闀�******/
+    public static final int DEFAULT_RECONNECT_INTERVAL = 3 * 1000;
+    public static final int CONNECT_STATE_CONNECTING = 0;
+    public static final int CONNECT_STATE_SUCCESSFUL = 1;
+    public static final int DEFAULT_RECONNECT_COUNT = 3;
+}
diff --git a/im_lib/src/main/java/com/anyun/im_lib/LoginAuthRespHandler.java b/im_lib/src/main/java/com/anyun/im_lib/LoginAuthRespHandler.java
new file mode 100644
index 0000000..6ebb52d
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/LoginAuthRespHandler.java
@@ -0,0 +1,42 @@
+package com.anyun.im_lib;
+
+import android.util.Log;
+
+import com.anyun.im_lib.interf.IMSClientInteface;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+
+/**
+ * MyApplication2
+ * 璁惧閴存潈
+ * Created by lzw on 2019/12/4. 11:25:33
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public class LoginAuthRespHandler extends  ChannelInboundHandlerAdapter {
+    
+    private static final String TAG = LoginAuthRespHandler.class.getSimpleName();
+    private IMSClientInteface imsClient;
+
+    /**
+     * 鏋勯�犲嚱鏁�
+     * @param imsClient
+     */
+    public LoginAuthRespHandler(IMSClientInteface imsClient) {
+        this.imsClient = imsClient;
+    }
+
+    @Override
+    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
+        super.channelReadComplete(ctx);
+        Log.i(TAG, "channelReadComplete");
+    }
+
+    @Override
+    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+        super.channelRead(ctx, msg);
+        Log.i(TAG, "channelRead"+(String)msg);
+        // TODO: 2019/12/4  
+    }
+}
diff --git a/im_lib/src/main/java/com/anyun/im_lib/MsgDispatcher.java b/im_lib/src/main/java/com/anyun/im_lib/MsgDispatcher.java
new file mode 100644
index 0000000..9fbc31e
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/MsgDispatcher.java
@@ -0,0 +1,25 @@
+package com.anyun.im_lib;
+
+import com.anyun.im_lib.listener.OnEventListener;
+
+/**
+ * MyApplication2
+ * Created by lzw on 2019/12/2. 14:02:14
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public class MsgDispatcher {
+
+    private OnEventListener onEventListener;
+
+    public void setOnEventListener(OnEventListener listener) {
+        this.onEventListener = listener;
+    }
+
+    public void receivedMsg(String msg){
+        // TODO: 2019/12/12
+        if (onEventListener != null){
+            onEventListener.dispatchMsg(msg);
+        }
+    }
+}
diff --git a/im_lib/src/main/java/com/anyun/im_lib/MsgTimeOutTimerManager.java b/im_lib/src/main/java/com/anyun/im_lib/MsgTimeOutTimerManager.java
new file mode 100644
index 0000000..33635fb
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/MsgTimeOutTimerManager.java
@@ -0,0 +1,33 @@
+package com.anyun.im_lib;
+
+import com.anyun.im_lib.interf.IMSClientInteface;
+import com.anyun.im_lib.netty.NettyTcpClient;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * MyApplication2
+ * Created by lzw on 2019/12/2. 14:03:15
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public class MsgTimeOutTimerManager {
+    private IMSClientInteface imsClient;
+    private Map<String,MsgTimeoutTimer> mMsgTimeoutMap = new HashMap<>();
+
+    public MsgTimeOutTimerManager(NettyTcpClient nettyTcpClient) {
+        this.imsClient = nettyTcpClient;
+    }
+
+    /**
+     * 娣诲姞娑堟伅鍒板彂閫佽秴鏃剁鐞嗗櫒
+     * @param message
+     */
+    public void add(String message){
+
+        if (message == null ){
+
+        }
+    }
+}
diff --git a/im_lib/src/main/java/com/anyun/im_lib/MsgTimeoutTimer.java b/im_lib/src/main/java/com/anyun/im_lib/MsgTimeoutTimer.java
new file mode 100644
index 0000000..eaf3747
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/MsgTimeoutTimer.java
@@ -0,0 +1,36 @@
+package com.anyun.im_lib;
+
+import android.util.Log;
+
+import com.anyun.im_lib.interf.IMSClientInteface;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * MyApplication2
+ * Created by lzw on 2019/12/2. 15:09:39
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public class MsgTimeoutTimer extends Timer {
+    private static final String TAG = "MsgTimeoutTimer";
+    private IMSClientInteface imsClient;
+    private Object message;//鍙戦�佺殑娑堟伅
+    private  int currentResendCount;//褰撳墠閲嶅彂娆℃暟
+    private  MsgTimeoutTask task;//娑堟伅鍙戦�佽秴鏃朵换鍔�
+
+    public MsgTimeoutTimer(IMSClientInteface imsClient) {
+        Log.i(TAG, "MsgTimeoutTimer: ");
+        this.imsClient = imsClient;
+        this.schedule(task,imsClient.getResendInterval(),imsClient.getResendInterval());
+    }
+
+    private class MsgTimeoutTask extends TimerTask{
+
+        @Override
+        public void run() {
+
+        }
+    }
+}
diff --git a/im_lib/src/main/java/com/anyun/im_lib/im/IMSClientBootstrap.java b/im_lib/src/main/java/com/anyun/im_lib/im/IMSClientBootstrap.java
new file mode 100644
index 0000000..d4d001c
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/im/IMSClientBootstrap.java
@@ -0,0 +1,61 @@
+package com.anyun.im_lib.im;
+
+import android.util.Log;
+
+import com.anyun.im_lib.IMSClientFactory;
+import com.anyun.im_lib.interf.IMSClientInteface;
+
+import java.util.Vector;
+
+import static android.content.ContentValues.TAG;
+
+/**
+ * MyApplication2
+ * Created by lzw on 2019/12/2. 11:56:55
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public class IMSClientBootstrap {
+
+    private static final IMSClientBootstrap INSTANCE= new IMSClientBootstrap();
+    private IMSClientInteface imsClient;
+
+    /**鏍囪IMSClientBootstrap鏄惁宸茬粡鍒濆鍖�**/
+    private boolean isAlive;
+
+    /**
+     * 
+     * @param userId
+     * @param token
+     * @param hosts
+     * @param appStatus
+     */
+    public synchronized void init(String userId,String token,String hosts,int appStatus){
+        if (!isAlive){
+            Vector<String> serverUrlList = convertHosts(hosts);
+            if (serverUrlList == null || serverUrlList.size() ==0){
+                Log.i(TAG, "init IMLibClientBootstrap error,ims hosts is null");
+                return;
+            }
+            isAlive = true;
+            Log.i(TAG, "init IMLibClientBootstrap ,server="+hosts);
+        }
+        if (null != imsClient){
+            imsClient.close();
+        }
+        //鍒濆鍖朓MSClientInteface
+        imsClient = IMSClientFactory.getIMSClient();
+        updateAppStatus(appStatus);
+//        imsClient.init(serverUrlList,new OnEventListener(userId,token),new IMSConnectStatusCallback());
+    }
+
+
+
+    private void updateAppStatus(int appStatus) {
+    }
+
+    private Vector<String> convertHosts(String hosts) {
+        //TODO
+        return null;
+    }
+}
diff --git a/im_lib/src/main/java/com/anyun/im_lib/interf/IMSClientInteface.java b/im_lib/src/main/java/com/anyun/im_lib/interf/IMSClientInteface.java
new file mode 100644
index 0000000..2f04a29
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/interf/IMSClientInteface.java
@@ -0,0 +1,114 @@
+package com.anyun.im_lib.interf;
+
+import com.anyun.im_lib.MsgDispatcher;
+import com.anyun.im_lib.MsgTimeOutTimerManager;
+import com.anyun.im_lib.listener.IMSConnectStatusCallback;
+import com.anyun.im_lib.listener.OnEventListener;
+
+import java.util.Vector;
+
+/**
+ * MyApplication2
+ * Created by lzw on 2019/12/2. 11:58:51
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public interface IMSClientInteface {
+    /**
+     * 鍒濆鍖�
+     * @param serverUrlList
+     * @param listener
+     * @param callback
+     */
+    void init(Vector<String> serverUrlList, OnEventListener listener, IMSConnectStatusCallback callback);
+
+    /**
+     * 閲嶇疆杩炴帴锛屼篃灏辨槸閲嶈繛
+     * 棣栨杩炴帴涔熷彲璁や负鏄噸杩�
+     */
+    void resetConnect();
+    /**
+     * 閲嶇疆杩炴帴锛屼篃灏辨槸閲嶈繛
+     * 棣栨杩炴帴涔熷彲璁や负鏄噸杩�
+     * 閲嶈浇
+     * @param isFirst  鏄惁棣栨杩炴帴
+     */
+    void resetConnect(boolean isFirst);
+
+    /**
+     * 鍏抽棴杩炴帴锛屽悓鏃堕噴鏀捐祫婧�
+     */
+    void close();
+
+    /**
+     * 琛ㄧずims鏄惁宸茬粡鍏抽棴
+     * @return
+     */
+    boolean isClosed();
+
+    /**
+     * 鍙戦�佹秷鎭�
+     * @param msg
+     */
+    void sendMsg(String msg);
+
+    /**
+     * 鍙戦�佹秷鎭�
+     * 閲嶈浇
+     * @param msg
+     * @param isJoinTimeoutManager 鏄惁鍔犲叆瓒呮椂绠$悊鍣�
+     */
+    void sendMsg(String msg, boolean isJoinTimeoutManager);
+
+    /**
+     * 鑾峰彇閲嶈繛闂撮殧鏃堕暱
+     * @return
+     */
+    int getReconnectInterval();
+
+
+    /**
+     * 鑾峰彇杩為棿闅旀椂闀�
+     * @return
+     */
+    int getConnectTimeout();
+    /**
+     * 鑾峰彇搴旂敤鍦ㄥ墠鍙版椂蹇冭烦闂撮殧
+     * @return
+     */
+    int getForegroundHeartbeatInterval();
+
+    /**
+     * 璁剧疆app鍓嶅悗鍙扮姸鎬�
+     * @param appStatus
+     */
+    void setAppStatus(int appStatus);
+
+    /**
+     * 鑾峰彇搴旂敤鍦ㄥ悗鍙版椂蹇冭烦闂撮殧
+     * @return
+     */
+    int getBackgroundHeartbeatInterval();
+
+    /**
+     * 鑾峰彇搴旂敤灞傛秷鎭彂閫佽秴鏃堕噸鍙戞鏁�
+     * @return
+     */
+    int getResendCount();
+
+    /**
+     * 鑾峰彇搴旂敤灞傛秷鎭彂閫佽秴鏃堕棿闅�
+     * @return
+     */
+    int getResendInterval();
+
+    /**
+     * 鑾峰彇娑堟伅杞彂鍣�
+     * @return
+     */
+    MsgDispatcher getMsgDispatcher();
+
+    MsgTimeOutTimerManager getMsgTimeOutTimerManager();
+
+
+}
diff --git a/im_lib/src/main/java/com/anyun/im_lib/listener/IMSConnectStatusCallback.java b/im_lib/src/main/java/com/anyun/im_lib/listener/IMSConnectStatusCallback.java
new file mode 100644
index 0000000..8a5dccc
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/listener/IMSConnectStatusCallback.java
@@ -0,0 +1,20 @@
+package com.anyun.im_lib.listener;
+
+/**
+ * MyApplication2
+ * Created by lzw on 2019/12/2. 13:18:05
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public interface IMSConnectStatusCallback {
+    /***ims杩炴帴涓�*/
+    void onConnecting();
+
+    /***ims杩炴帴鎴愬姛**/
+    void onConnected();
+
+    /***ims杩炴帴澶辫触**/
+    void onConnectFailed();
+
+
+}
diff --git a/im_lib/src/main/java/com/anyun/im_lib/listener/OnEventListener.java b/im_lib/src/main/java/com/anyun/im_lib/listener/OnEventListener.java
new file mode 100644
index 0000000..be3e606
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/listener/OnEventListener.java
@@ -0,0 +1,60 @@
+package com.anyun.im_lib.listener;
+
+/**
+ * MyApplication2
+ * Created by lzw on 2019/12/2. 13:17:49
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public interface OnEventListener {
+    /**
+     * 鍒嗗彂娑堟伅鍒板簲鐢ㄥ眰
+     * @param message
+     */
+    void dispatchMsg(Object  message);
+
+    /**
+     * 浠庡簲鐢ㄥ眰鑾峰彇缃戠粶鏄惁鍙敤
+     * @return
+     */
+    boolean isNetWorkAvailable();
+
+    /**
+     * 鑾峰彇閲嶈繛闂撮殧鏃堕暱
+     * @return
+     */
+    int getConnectTimeout();
+
+    /**
+     * 鑾峰彇搴旂敤鍦ㄥ墠鍙版椂蹇冭烦闂撮殧
+     * @return
+     */
+    int getForegroundHeartbeatInterval();
+
+    /**
+     * 鑾峰彇搴旂敤鍦ㄥ悗鍙版椂蹇冭烦闂撮殧
+     * @return
+     */
+    int getBackgroundHeartbeatInterval();
+
+
+    /**
+     * 鑾峰彇搴旂敤灞傛秷鎭彂閫佺姸鎬佹姤鍛婃秷鎭被鍨�
+     * @return
+     */
+    int getServerSentReportMsgType();
+
+    /**
+     * 鑾峰彇搴旂敤灞傛秷鎭彂閫佽秴鏃堕噸鍙戞鏁�
+     * @return
+     */
+    int getResendCount();
+
+    /**
+     * 鑾峰彇搴旂敤灞傛秷鎭彂閫佽秴鏃堕棿闅�
+     * @return
+     */
+    int getResendInterval();
+
+    int getReConnectInterval();
+}
diff --git a/im_lib/src/main/java/com/anyun/im_lib/netty/NettyTcpClient.java b/im_lib/src/main/java/com/anyun/im_lib/netty/NettyTcpClient.java
new file mode 100644
index 0000000..3867e0d
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/netty/NettyTcpClient.java
@@ -0,0 +1,497 @@
+package com.anyun.im_lib.netty;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.anyun.im_lib.ExecutorServiceFactory;
+import com.anyun.im_lib.HeartbeatHandler;
+import com.anyun.im_lib.IMSConfig;
+import com.anyun.im_lib.MsgDispatcher;
+import com.anyun.im_lib.MsgTimeOutTimerManager;
+import com.anyun.im_lib.interf.IMSClientInteface;
+import com.anyun.im_lib.listener.IMSConnectStatusCallback;
+import com.anyun.im_lib.listener.OnEventListener;
+
+import java.util.Vector;
+import java.util.function.ToDoubleBiFunction;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.timeout.IdleStateHandler;
+
+
+/**
+ * MyApplication2
+ * Created by lzw on 2019/12/2. 13:14:52
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public class NettyTcpClient implements IMSClientInteface {
+
+    private static final String TAG = NettyTcpClient.class.getSimpleName();
+
+    private static volatile NettyTcpClient instance;
+
+    private Bootstrap bootstrap;
+    private Channel channel;
+
+    /****鏍囪瘑IMS鏄惁宸插叧闂�***/
+    private boolean isClosed = false;
+
+    /****ims鏈嶅姟鍣ㄥ湴鍧�缁�***/
+    private Vector<String> serverUrlList;
+
+    /****涓庡簲鐢ㄥ眰浜や簰鐨刲istener***/
+    private OnEventListener mOnEventListener;
+    /*** ims杩炴帴鐘舵�佸洖璋冪洃鍚櫒**/
+    private IMSConnectStatusCallback imsConnectStatusCallback;
+
+    /****娑堟伅杞彂鍣�***/
+    private MsgDispatcher msgDispatcher;
+
+    /***绾跨▼姹犲伐鍘�**/
+    private ExecutorServiceFactory loopGroup;
+
+    /****鏄惁姝e湪杩涜閲嶈繛***/
+    private boolean isReconnecting = false;
+    /*** ims杩炴帴鐘舵�侊紝鍒濆鍖栦负杩炴帴澶辫触 ***/
+    private int connectStatus = IMSConfig.CONNECT_STATE_FAILURE;
+
+    /*** 閲嶈繛闂撮殧鏃堕暱 ***/
+    private int reconnectInterval = IMSConfig.DEFAULT_RECONNECT_BASE_DELAY_TIME;
+    /*** 杩炴帴瓒呮椂鏃堕暱 ***/
+    private int connectTimeOut = IMSConfig.DEFAULT_CONNECT_TIMEOUT;
+
+    private int heartBeatInterval = IMSConfig.DEFAULT_HEARTBEAT_INTERVAL_FOREGROUND;
+    private int foregroundHeartBeatInterval = IMSConfig.DEFAULT_HEARTBEAT_INTERVAL_FOREGROUND;
+    private int backgroundHeartBeatInterval = IMSConfig.DEFAULT_HEARTBEAT_INTERVAL_BACKGROUND;
+
+    private int appStatus = IMSConfig.APP_STATUS_FOREGROUND;
+    /*** 娑堟伅鍙戦�佽秴鏃堕噸鍙戞鏁�***/
+    private int resendCount = IMSConfig.DEFAULT_RESEND_COUNT;
+    /*** 娑堟伅鍙戦�佸け璐ラ噸鍙戦棿闅旀椂闀�***/
+    private int resendInterval = IMSConfig.DEFAULT_RESEND_INTERVAL;
+
+    /*** 褰撳墠杩炴帴host***/
+    private String currentHost = null;
+    /*** 褰撳墠杩炴帴port***/
+    private int currentPort = -1;
+    /*** 娑堟伅鍙戦�佽秴鏃跺畾鏃剁鐞嗗櫒***/
+    private MsgTimeOutTimerManager msgTimeOutTimerManager;
+
+
+    private NettyTcpClient(){
+
+    }
+
+    public static IMSClientInteface getInstance() {
+        if (null == instance){
+            synchronized (NettyTcpClient.class){
+                if (null==instance){
+                    instance = new NettyTcpClient();
+                }
+            }
+        }
+        return instance;
+    }
+
+    /**
+     * 鍒濆鍖�
+     * @param serverUrlList 鏈嶅姟鍣ㄥ湴鍧�鍒楄〃
+     * @param listener 涓庡簲鐢ㄥ眰浜や簰鐨刲istener
+     * @param callback ims杩炴帴鐘舵�佸洖璋�
+     */
+    @Override
+    public void init(Vector<String> serverUrlList, OnEventListener listener, IMSConnectStatusCallback callback) {
+        close();
+        isClosed = false;
+        this.serverUrlList = serverUrlList;
+        this.mOnEventListener = listener;
+        this.imsConnectStatusCallback = callback;
+        msgDispatcher = new MsgDispatcher();
+        msgDispatcher.setOnEventListener(listener);
+        loopGroup = new ExecutorServiceFactory();
+        loopGroup.initBossLoopGroup();
+        msgTimeOutTimerManager = new MsgTimeOutTimerManager(this);
+        /*** 杩涜绗竴娆¤繛鎺�***/
+        resetConnect(true);
+    }
+
+    @Override
+    public void resetConnect() {
+        this.resetConnect(false);
+    }
+
+    @Override
+    public void resetConnect(boolean isFirst) {
+        if (!isFirst){
+            try {
+                Thread.sleep(IMSConfig.DEFAULT_RECONNECT_INTERVAL);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+        //鍙湁绗竴涓皟鐢ㄨ�呮墠鑳借祴鍊煎苟璋冪敤閲嶈繛
+        if (!isClosed && !isReconnecting){
+            synchronized (this){
+                if (!isClosed && !isReconnecting){
+                    //鏍囪瘑閲嶈繛浠诲姟杩涜涓�...
+                    isReconnecting = true;
+
+                    onConnectStatusCallback(IMSConfig.CONNECT_STATE_CONNECTING);
+                    closeChannel();
+                    loopGroup.execBossTask(new ResetConnectRunnable(isFirst));
+                }
+            }
+        }
+    }
+
+
+
+
+    /***
+     * 鍒濆鍖朆ootstrap
+     */
+    private void initBootstrap() {
+        EventLoopGroup loopGroup = new NioEventLoopGroup(4);
+        bootstrap = new Bootstrap();
+        bootstrap.group(loopGroup).channel(NioSocketChannel.class);
+        // 璁剧疆璇ラ」浠ュ悗锛屽鏋滃湪涓ゅ皬鏃跺唴娌℃湁鏁版嵁閫氫俊鏃讹紝TCP浼氳嚜鍔ㄥ彂閫佷竴涓椿鍔ㄦ帰娴嬫暟鎹姤鏂�
+        bootstrap.option(ChannelOption.SO_KEEPALIVE,true);
+        //璁剧疆绂佺敤nagle绠楁硶
+        bootstrap.option(ChannelOption.TCP_NODELAY,true);
+        bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,getConnectTimeout());
+        bootstrap.handler(new TCPChannelInitializerHandler(this));
+    }
+
+
+    /**
+     * 鐪熸杩炴帴鏈嶅姟鍣ㄧ殑鍦版柟
+     */
+    private void toServer() {
+        try {
+            channel = bootstrap.connect(currentHost,currentPort).sync().channel();
+        } catch (InterruptedException e) {
+            try {
+                Thread.sleep(500);
+            } catch (InterruptedException ex) {
+                ex.printStackTrace();
+            }
+
+            Log.i(TAG, String.format("杩炴帴Server(ip[%s],port[%d]澶辫触)",currentHost,currentPort));
+            channel = null;
+        }
+    }
+
+    private boolean isNetworkAvaliable() {
+        if (mOnEventListener != null){
+            return mOnEventListener.isNetWorkAvailable();
+        }
+        return false;
+    }
+
+    /**
+     * 鍥炶皟ims杩炴帴鐘舵��
+     * @param connectStateConnecting
+     */
+    private void onConnectStatusCallback(int connectStateConnecting) {
+        this.connectStatus = connectStateConnecting;
+        switch (connectStatus){
+            case IMSConfig.CONNECT_STATE_CONNECTING:
+                Log.i(TAG, "onConnectStatusCallback: ims杩炴帴涓�...");
+                if (imsConnectStatusCallback != null){
+                    imsConnectStatusCallback.onConnecting();
+                }
+                break;
+            case IMSConfig.CONNECT_STATE_SUCCESSFUL:
+                Log.i(TAG, String.format("onConnectStatusCallback: ims杩炴帴鎴愬姛锛宧ost[%s],port[%s]",currentHost,currentPort));
+                if (imsConnectStatusCallback != null){
+                    imsConnectStatusCallback.onConnected();
+                }
+                // TODO: 2019/12/12  杩炴帴鎴愬姛 锛屽彂閫佹彙鎵嬫秷鎭紙闇�瑕佺殑璇濃�斺�旓級
+                break;
+            case IMSConfig.CONNECT_STATE_FAILURE:
+                default:
+                    Log.i(TAG, "onConnectStatusCallback: ims杩炴帴澶辫触");
+                    if (imsConnectStatusCallback != null){
+                        imsConnectStatusCallback.onConnectFailed();
+                    }
+                    break;
+        }
+    }
+
+    /**
+     * 鍏抽棴杩炴帴锛屽悓鏃堕噴鏀捐祫婧�
+     */
+    @Override
+    public void close() {
+        if (isClosed){
+            return;
+        }
+        isClosed = true;
+        /*** 鍏抽棴channel***/
+        try {
+            closeChannel();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        /*** 鍏抽棴bootstrap ***/
+        try {
+            if (bootstrap != null){
+                bootstrap.group().shutdownGracefully();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        /*** 閲婃斁绾跨▼姹� ***/
+        try {
+            if (loopGroup != null){
+                loopGroup.destroy();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (serverUrlList != null){
+                    serverUrlList.clear();
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+            isReconnecting = false;
+            channel = null;
+            bootstrap = null;
+        }
+    }
+
+    private void closeChannel() {
+        if (channel != null){
+            removeHandler(HeartbeatHandler.class.getSimpleName());
+            removeHandler(TCPReadHandler.class.getSimpleName());
+            removeHandler(IdleStateHandler.class.getSimpleName());
+        }
+    }
+
+    /**
+     * 绉婚櫎鎸囧畾handler
+     * @param handlerName
+     */
+    private void removeHandler(String handlerName) {
+        try {
+            if (channel.pipeline().get(handlerName) != null){
+                channel.pipeline().remove(handlerName);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            Log.i(TAG, "removeHandler fail,handlerName="+handlerName);
+        }
+    }
+
+    @Override
+    public boolean isClosed() {
+        return false;
+    }
+
+    @Override
+    public void sendMsg(String msg) {
+        this.sendMsg(msg,true);
+    }
+
+    /**
+     *
+     * @param msg
+     * @param isJoinTimeoutManager 鏄惁鍔犲叆瓒呮椂绠$悊鍣�
+     */
+    @Override
+    public void sendMsg(String msg, boolean isJoinTimeoutManager) {
+        if (msg==null ){
+            return;
+        }
+        // TODO: 2019/12/12  鏍规嵁MSG_ID 鏉ュ姞鍏� 瓒呮椂锛�  鏆備笉鍐�
+
+        if (channel == null){
+            Log.i(TAG, "sendMsg fail,channel涓虹┖"+msg);
+        }
+        try {
+            channel.writeAndFlush(msg);
+        } catch (Exception e) {
+            Log.i(TAG, "鍙戦�佹秷鎭け璐ワ紝reason="+e.getMessage()+"\t"+msg);
+        }
+    }
+
+    /**
+     * 鑾峰彇瀹㈡埛璁剧疆鐨勯噸杩炴椂闀�
+     * @return
+     */
+    @Override
+    public int getReconnectInterval() {
+        if (mOnEventListener != null && mOnEventListener.getReConnectInterval()>0){
+            return reconnectInterval = mOnEventListener.getReConnectInterval();
+        }
+        return reconnectInterval;
+    }
+
+    @Override
+    public int getConnectTimeout() {
+        return 0;
+    }
+
+    @Override
+    public int getForegroundHeartbeatInterval() {
+        return 0;
+    }
+
+    @Override
+    public void setAppStatus(int appStatus) {
+
+    }
+
+    @Override
+    public int getBackgroundHeartbeatInterval() {
+        return 0;
+    }
+
+    @Override
+    public int getResendCount() {
+        return 0;
+    }
+
+    @Override
+    public int getResendInterval() {
+        return 0;
+    }
+
+    @Override
+    public MsgDispatcher getMsgDispatcher() {
+        return msgDispatcher;
+    }
+
+    @Override
+    public MsgTimeOutTimerManager getMsgTimeOutTimerManager() {
+        return msgTimeOutTimerManager;
+    }
+
+
+    /**
+     * 閲嶈繛浠诲姟
+     */
+    private class ResetConnectRunnable implements Runnable{
+        private boolean isFirst;
+        public ResetConnectRunnable(boolean isFirst) {
+            this.isFirst = isFirst;
+        }
+
+        @Override
+        public void run() {
+            if (!isFirst){
+                onConnectStatusCallback(IMSConfig.CONNECT_STATE_FAILURE);
+            }
+            try {
+                //閲嶈繛鏃讹紝閲婃斁宸ヤ綔缁勭嚎绋嬫睜锛屼篃灏辨槸鍋滄蹇冭烦
+                loopGroup.destroyWorkLoopGroup();
+                while (!isClosed){
+                    if (!isNetworkAvaliable()){
+                        try {
+                            Thread.sleep(2000);
+                        } catch (InterruptedException e) {
+                            e.printStackTrace();
+                        }
+                        continue;
+                    }
+                    //缃戠粶鍙敤鎵嶈繘琛岃繛鎺�
+                    int status;
+                    if ((status=reConnect()) == IMSConfig.CONNECT_STATE_SUCCESSFUL){
+                        onConnectStatusCallback(status);
+                        //杩炴帴鎴愬姛锛岃皟鍑哄惊鐜�
+                        break;
+                    }
+
+                    if (status == IMSConfig.CONNECT_STATE_FAILURE){
+                        onConnectStatusCallback(status);
+                        try {
+                            Thread.sleep(IMSConfig.DEFAULT_RECONNECT_INTERVAL);
+                        } catch (InterruptedException e) {
+                            e.printStackTrace();
+                        }
+                    }
+                }
+            } finally {
+                //鏍囪瘑閲嶈繛浠诲姟鍋滄
+                isReconnecting = false;
+            }
+        }
+
+        /**
+         * 閲嶈繛锛岄娆¤繛鎺ヤ篃璁や负鏄涓�娆¢噸杩�
+         * @return
+         */
+        private int reConnect() {
+            if (!isClosed){
+                try {
+                    //鍏堥噴鏀綞ventLoop绾跨▼缁�
+                    if (bootstrap != null){
+                        bootstrap.group().shutdownGracefully();
+                    }
+                } finally {
+                    bootstrap = null;
+                }
+                initBootstrap();
+                return connectServer();
+            }
+            return IMSConfig.CONNECT_STATE_FAILURE;
+        }
+
+        private int connectServer(){
+            //鏈嶅姟鍣ㄥ湴鍧�鏃犳晥锛岀洿鎺ュ洖璋冭繛鎺ョ姸鎬侊紝涓嶅啀杩涜杩炴帴
+            if (serverUrlList == null || serverUrlList.size() == 0){
+                return IMSConfig.CONNECT_STATE_FAILURE;
+            }
+            for (int i = 0; i < serverUrlList.size(); i++) {
+                String serverUrl = serverUrlList.get(i);
+                //鏈嶅姟鍣ㄥ湴鍧�鏃犳晥锛岀洿鎺ュ洖璋冭繛鎺ョ姸鎬侊紝涓嶅啀杩涜杩炴帴
+                if (TextUtils.isEmpty(serverUrl)){
+                    return IMSConfig.CONNECT_STATE_FAILURE;
+                }
+                String[] address = serverUrl.split(" ");
+                for (int j = 0; j < IMSConfig.DEFAULT_RECONNECT_COUNT; j++) {
+                    //濡傛灉ims宸茬粡鍏抽棴锛屾垨缃戠粶涓嶅彲鐢紝鐩存帴鍥炶皟杩炴帴鐘舵�侊紝涓嶅啀杩涜杩炴帴
+                    if (isClosed || !isNetworkAvaliable()){
+                        return IMSConfig.CONNECT_STATE_FAILURE;
+                    }
+                    //鍥炶皟杩炴帴鐘舵��
+                    if(connectStatus != IMSConfig.CONNECT_STATE_CONNECTING){
+                        onConnectStatusCallback(IMSConfig.CONNECT_STATE_CONNECTING);
+                    }
+                    Log.i(TAG, String.format("姝e湪杩涜connectServer銆�%s銆戠殑绗琜%d]杩炴帴锛屽綋鍓嶉噸杩炲欢鏃舵椂闀夸负[%dms]: ",serverUrl,j,j*getReconnectInterval()));
+                    try {
+                        currentPort = Integer.parseInt(address[1]);
+                        currentHost = address[0];
+                        //杩炴帴鏈嶅姟鍣�
+                        toServer();
+                        //channel涓嶄负绌猴紝鍒欒涓鸿繛鎺ュ凡缁忔垚鍔�
+                        if(channel != null){
+                            return IMSConfig.CONNECT_STATE_SUCCESSFUL;
+                        }else{
+                            Thread.sleep(j*getReconnectInterval());
+                        }
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                        close();
+                        break;
+                    }
+                }
+            }
+            return IMSConfig.CONNECT_STATE_FAILURE;
+        }
+
+    }
+
+
+
+
+}
diff --git a/im_lib/src/main/java/com/anyun/im_lib/netty/TCPChannelInitializerHandler.java b/im_lib/src/main/java/com/anyun/im_lib/netty/TCPChannelInitializerHandler.java
new file mode 100644
index 0000000..721707e
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/netty/TCPChannelInitializerHandler.java
@@ -0,0 +1,64 @@
+package com.anyun.im_lib.netty;
+
+import com.anyun.im_lib.HeartbeatRespHandler;
+import com.anyun.im_lib.LoginAuthRespHandler;
+import com.anyun.im_lib.interf.IMSClientInteface;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.handler.codec.FixedLengthFrameDecoder;
+import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
+
+/**
+ * MyApplication2
+ * channel鍒濆鍖�
+ * Created by lzw on 2019/12/2. 15:56:39
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public class TCPChannelInitializerHandler  extends ChannelInitializer<Channel> {
+
+    private IMSClientInteface imsClient;
+
+    public TCPChannelInitializerHandler(NettyTcpClient nettyTcpClient) {
+        this.imsClient = nettyTcpClient;
+    }
+
+    @Override
+    protected void initChannel(Channel channel) throws Exception {
+        ChannelPipeline pipeline = channel.pipeline();
+
+        //netty鎻愪緵鐨勮嚜瀹氫箟闀垮害瑙g爜鍣紝瑙e喅TP鎷嗗寘/绮樺寘闂
+
+        // TODO: 2019/12/4
+//        锛�1锛� maxFrameLength - 鍙戦�佺殑鏁版嵁鍖呮渶澶ч暱搴︼紱
+//
+//锛�2锛� lengthFieldOffset - 闀垮害鍩熷亸绉婚噺锛屾寚鐨勬槸闀垮害鍩熶綅浜庢暣涓暟鎹寘瀛楄妭鏁扮粍涓殑涓嬫爣锛�
+//
+//锛�3锛� lengthFieldLength - 闀垮害鍩熺殑鑷繁鐨勫瓧鑺傛暟闀垮害銆�
+//
+//锛�4锛� lengthAdjustment 鈥� 闀垮害鍩熺殑鍋忕Щ閲忕煫姝c�� 濡傛灉闀垮害鍩熺殑鍊硷紝闄や簡鍖呭惈鏈夋晥鏁版嵁鍩熺殑闀垮害澶栵紝杩樺寘鍚簡鍏朵粬鍩燂紙濡傞暱搴﹀煙鑷韩锛夐暱搴︼紝閭d箞锛屽氨闇�瑕佽繘琛岀煫姝c�傜煫姝g殑鍊间负锛氬寘闀� - 闀垮害鍩熺殑鍊� 鈥� 闀垮害鍩熷亸绉� 鈥� 闀垮害鍩熼暱銆�
+//
+//锛�5锛� initialBytesToStrip 鈥� 涓㈠純鐨勮捣濮嬪瓧鑺傛暟銆備涪寮冨浜庢湁鏁堟暟鎹墠闈㈢殑瀛楄妭鏁伴噺銆傛瘮濡傚墠闈㈡湁4涓妭鐐圭殑闀垮害鍩燂紝鍒欏畠鐨勫�间负4銆�
+//
+//        鍦ㄤ笂闈㈢殑渚嬪瓙涓紝鑷畾涔夐暱搴﹁В鐮佸櫒鐨勬瀯閫犲弬鏁板�煎涓嬶細
+//
+//        LengthFieldBasedFrameDecoder spliter=new LengthFieldBasedFrameDecoder(1024,0,4,0,4);
+//        绗竴涓弬鏁颁负1024锛岃〃绀烘暟鎹寘鐨勬渶澶ч暱搴︿负1024锛涚浜屼釜鍙傛暟0锛岃〃绀洪暱搴﹀煙鐨勫亸绉婚噺涓�0锛屼篃灏辨槸闀垮害鍩熸斁鍦ㄤ簡鏈�鍓嶉潰锛屽浜庡寘鐨勮捣濮嬩綅缃紱绗笁涓弬鏁颁负4锛岃〃绀洪暱搴﹀煙鍗犵敤4涓瓧鑺傦紱绗洓涓弬鏁颁负0锛岃〃绀洪暱搴﹀煙淇濆瓨鐨勫�硷紝浠呬粎涓烘湁鏁堟暟鎹暱搴︼紝涓嶅寘鍚叾浠栧煙锛堝闀垮害鍩燂級鐨勯暱搴︼紱绗簲涓弬鏁颁负4锛岃〃绀烘渶缁堢殑鍙栧埌鐨勭洰鏍囨暟鎹寘锛屾姏寮冩渶鍓嶉潰鐨�4涓瓧鑺傛暟鎹紝闀垮害鍩熺殑鍊艰鎶涘純銆�
+//
+//        涓轰簡鏇村姞娓呮鐨勮鏄庝竴涓嬩笂闈㈢殑瑙勫垯锛岃皟鏁翠竴涓嬩緥瀛愪腑鐨勪唬鐮併�傚湪鍐欏叆閫氶亾鍓嶏紝鍦ㄦ暟鎹�
+//        pipeline.addLast(new LengthFieldBasedFrameDecoder(1024,3 ,4,0,13));
+
+        pipeline.addLast(new FixedLengthFrameDecoder(31));  // 娴嬭瘯鐢�  鍥哄畾闀垮害娑堟伅
+
+        //鎻℃墜璁よ瘉娑堟伅鐩稿簲澶勭悊handler
+        pipeline.addLast(LoginAuthRespHandler.class.getSimpleName(), new LoginAuthRespHandler(imsClient));
+
+        //蹇冭烦娑堟伅鍝嶅簲澶勭悊handler
+        pipeline.addLast(HeartbeatRespHandler.class.getSimpleName(), new HeartbeatRespHandler(imsClient));
+
+        //鎺ユ敹娑堟伅澶勭悊handler
+        pipeline.addLast(TCPReadHandler.class.getSimpleName(),new TCPReadHandler(imsClient));
+    }
+}
diff --git a/im_lib/src/main/java/com/anyun/im_lib/netty/TCPReadHandler.java b/im_lib/src/main/java/com/anyun/im_lib/netty/TCPReadHandler.java
new file mode 100644
index 0000000..768ca32
--- /dev/null
+++ b/im_lib/src/main/java/com/anyun/im_lib/netty/TCPReadHandler.java
@@ -0,0 +1,66 @@
+package com.anyun.im_lib.netty;
+
+import android.util.Log;
+
+import com.anyun.im_lib.interf.IMSClientInteface;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+
+/**
+ * MyApplication2
+ * 娑堟伅鎺ユ敹澶勭悊handler
+ * Created by lzw on 2019/12/4. 10:58:43
+ * 閭锛�632393724@qq.com
+ * All Rights Saved! Chongqing AnYun Tech co. LTD
+ */
+public class TCPReadHandler extends ChannelInboundHandlerAdapter {
+
+    private static final String TAG = TCPReadHandler.class.getSimpleName();
+
+    private IMSClientInteface imsClient;
+
+    public TCPReadHandler(IMSClientInteface imsClient) {
+        this.imsClient = imsClient;
+    }
+
+    @Override
+    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+        super.channelActive(ctx);
+        Log.i(TAG, "channelInactive");
+        Channel channel = ctx.channel();
+        if (channel != null){
+            channel.close();
+            ctx.close();
+        }
+        //瑙﹀彂閲嶈繛
+        imsClient.resetConnect(false);
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+        super.exceptionCaught(ctx, cause);
+        Log.i(TAG, "exceptionCaught: "+cause.getMessage());
+        Channel channel = ctx.channel();
+        if (channel != null){
+            channel.close();
+        }
+        //瑙﹀彂閲嶈繛
+        imsClient.resetConnect(false);
+    }
+
+    @Override
+    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+        super.channelRead(ctx, msg);
+        // TODO: 2019/12/4
+        Log.i(TAG, "channelRead: ");
+        imsClient.getMsgDispatcher().receivedMsg((String)msg);
+    }
+
+    @Override
+    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
+        super.channelReadComplete(ctx);
+        Log.i(TAG, "channelReadComplete");
+    }
+}
diff --git a/im_lib/src/main/res/values/strings.xml b/im_lib/src/main/res/values/strings.xml
new file mode 100644
index 0000000..be8be32
--- /dev/null
+++ b/im_lib/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">im_lib</string>
+</resources>
diff --git a/im_lib/src/test/java/com/anyun/im_lib/ExampleUnitTest.java b/im_lib/src/test/java/com/anyun/im_lib/ExampleUnitTest.java
new file mode 100644
index 0000000..1b5198b
--- /dev/null
+++ b/im_lib/src/test/java/com/anyun/im_lib/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.anyun.im_lib;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+    @Test
+    public void addition_isCorrect() {
+        assertEquals(4, 2 + 2);
+    }
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 3cbe249..c3516ad 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':app', ':lib'
+include ':app', ':lib', ':im_lib'

--
Gitblit v1.8.0