ソースを参照

netty tcp client ok

allen 4 年 前
コミット
cc13289951

+ 4 - 2
app/build.gradle

@@ -103,12 +103,14 @@ dependencies {
      * JavaShopAndroid 中间件依赖库
      */
     compile project(':middleware')
-
     /**
      *  constraint-layout布局依赖
      */
     compile 'com.android.support.constraint:constraint-layout:1.1.0-beta5'
-
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+}
+repositories {
+    mavenCentral()
 }
 
 ///**

+ 7 - 6
build.gradle

@@ -62,9 +62,8 @@ buildscript {
             /**
              * 依赖仓储
              */
-            maven { url 'http://maven.aliyun.com/nexus/content/repositories/google' }
-            maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'}
-            maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
+            maven { url 'https://maven.aliyun.com/repository/public' }
+            maven { url 'https://maven.aliyun.com/repository/google'}
             maven { url 'https://jitpack.io' }
         }
         /**
@@ -92,15 +91,17 @@ buildscript {
          */
         classpath "org.aspectj:aspectjtools:$aspectj_version"
     }
+    repositories {
+        mavenCentral()
+    }
 }
 /**
  * 统一依赖仓储
  */
 allprojects {
     repositories {
-        maven { url 'http://maven.aliyun.com/nexus/content/repositories/google' }
-        maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'}
-        maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
+        maven { url 'https://maven.aliyun.com/repository/public' }
+        maven { url 'https://maven.aliyun.com/repository/google'}
         maven { url 'https://jitpack.io' }
     }
     tasks.withType(Javadoc) { // 新增

+ 6 - 3
common/build.gradle

@@ -155,9 +155,7 @@ dependencies {
      *  七巧板框架
      */
     compile 'com.alibaba.android:tangram:2.0.0@aar'
-    compile('com.alibaba.android:vlayout:1.2.6.1@aar') {
-        changing = true
-    }
+    compile('com.alibaba.android:vlayout:1.2.6.1@aar')
     compile 'com.alibaba.android:ultraviewpager:1.0.6.5@aar'
     compile('me.everything:overscroll-decor-android:1.0.1@aar') {
         transitive true
@@ -223,6 +221,11 @@ dependencies {
 
 
     compile 'com.github.pinguo-zhouwei:MZBannerView:v2.0.2'
+
+    /**
+     * netty
+     */
+    compile 'io.netty:netty-all:4.1.42.Final'
 }
 
 //tasks.withType(JavaCompile) {

+ 127 - 0
common/src/main/code/com/wdkl/ncs/android/lib/tcp/TcpClient.java

@@ -0,0 +1,127 @@
+package com.wdkl.ncs.android.lib.tcp;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.*;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.codec.string.StringEncoder;
+import io.netty.handler.timeout.IdleStateHandler;
+import io.netty.util.CharsetUtil;
+
+import java.util.Scanner;
+import java.util.concurrent.TimeUnit;
+
+//单例
+public class TcpClient {
+    private NioEventLoopGroup workGroup = new NioEventLoopGroup(2);
+    private Bootstrap bootstrap;
+
+    //数据处理
+    TcpClientHandler tcpClientHandler = new TcpClientHandler();
+    //是否运行中
+    public boolean isRunning = false;
+    //重试间隔
+    private Integer retrySeconds = 5;
+    //重试计数
+    private Integer retryTimes = 1;
+
+
+    //单例
+    private static class TcpClientHolder{
+        private static TcpClient instance = new TcpClient();
+    }
+
+    public static TcpClient getInstance(){
+        return TcpClientHolder.instance;
+    }
+
+    //初始化Netty Tcp Client 并连接
+    public void init(String serverIP, Integer serverPort, Integer heartBeatSeconds){
+        final Integer hbSeconds = heartBeatSeconds;
+        bootstrap = new Bootstrap();
+        bootstrap.group(workGroup)
+                .channel(NioSocketChannel.class)
+                .option(ChannelOption.SO_KEEPALIVE,true)
+                .handler(new ChannelInitializer<SocketChannel>() {
+                    @Override
+                    protected void initChannel(SocketChannel socketChannel) throws Exception {
+                        //心跳包应当小于服务器间隔
+                        socketChannel.pipeline().addLast(new IdleStateHandler(0, hbSeconds,0, TimeUnit.SECONDS));
+                        socketChannel.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));
+                        socketChannel.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));
+                        socketChannel.pipeline().addLast(tcpClientHandler);
+                    }
+                }).remoteAddress(serverIP,serverPort);
+        doConnect();
+    }
+
+    //独立连接方法,用于重新连接
+    public synchronized void doConnect(){
+        System.out.println("connect start");
+        ChannelFuture future = bootstrap.connect().addListener(new ChannelFutureListener() {
+            @Override
+            public void operationComplete(ChannelFuture channelFuture) throws Exception {
+                if (channelFuture.isSuccess()){
+                    isRunning = true;
+                    System.out.println("connect success");
+                } else {
+                    //连接失败时的处理
+                    isRunning = false;
+                    System.out.println("connect retry : " + retryTimes);
+                    channelFuture.channel().eventLoop().schedule(new Runnable() {
+                        @Override
+                        public void run() {
+                            retryTimes++;
+                            if (retryTimes>3){
+                                System.out.println("重试"+(retryTimes-1)+"次,结束");
+                                workGroup.shutdownGracefully();
+                                //todo: 从API获取新的serverIP和serverPort,全新连接
+                                //TcpClient.getInstance().init();
+                                return;
+                            }
+                            doConnect();
+                        }
+                    },retrySeconds * retryTimes, TimeUnit.SECONDS);
+                }
+            }
+        });
+        try {
+            future.sync();
+            future.channel().closeFuture().sync();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        } finally {
+            //重试之前不关
+//            try {
+//                Thread.sleep(retrySeconds * retryTimes*1000 + 1000);
+//            } catch (InterruptedException e) {
+//            }
+//            workGroup.shutdownGracefully();
+        }
+    }
+
+    //发送消息,线程安全
+    public synchronized void sendMsg(String content){
+        tcpClientHandler.sendMsg(content);
+    }
+
+    //测试
+    public static void main(String[] args) {
+
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                TcpClient.getInstance().init("192.168.1.188",5080, 9);
+            }
+        }).start();
+
+        Scanner scanner = new Scanner(System.in);
+        while (true){
+            System.out.println("please type : ");
+            String line = scanner.nextLine();
+            TcpClient.getInstance().sendMsg(line);
+        }
+    }
+}

+ 115 - 0
common/src/main/code/com/wdkl/ncs/android/lib/tcp/TcpClientHandler.java

@@ -0,0 +1,115 @@
+package com.wdkl.ncs.android.lib.tcp;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.timeout.IdleState;
+import io.netty.handler.timeout.IdleStateEvent;
+import io.netty.util.CharsetUtil;
+
+import java.util.concurrent.TimeUnit;
+
+@ChannelHandler.Sharable
+public class TcpClientHandler extends SimpleChannelInboundHandler<String> {
+    ChannelHandlerContext ctx;
+    //重连间隔
+    private static Integer retrySeconds = 5;
+    //重连计数
+    private static Integer retryTimes = 0;
+    //总共总连接次数,总连接次数过多可能是网络不稳定
+    private static Integer totalRetryTimes = 0;
+    //是否连接成功
+    private static Boolean connected = false;
+
+    //连接成功执行的方法
+    @Override
+    public void channelActive(ChannelHandlerContext ctx) throws Exception {
+        super.channelActive(ctx);
+        this.ctx = ctx;
+        connected = true;
+        retryTimes = 0;
+    }
+
+    //断开连接
+    @Override
+    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+        super.channelInactive(ctx);
+        connected = false;
+        System.out.println("失去连接");
+        reConnect(ctx);
+    }
+
+    //读取String消息
+    @Override
+    protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
+        System.out.println("channelRead0: read callback from server ===> " + s);
+    }
+
+    //写心跳包。没有消息发送时,每间隔一定时间会由此方法向服务端发送心跳
+    @Override
+    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+        if (evt instanceof IdleStateEvent){
+            IdleStateEvent event = (IdleStateEvent)evt;
+            if (event.state()== IdleState.WRITER_IDLE){
+                ctx.writeAndFlush(0);
+            }
+        }
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+        cause.printStackTrace();
+        ctx.close();
+        connected = false;
+        System.out.println("失去连接,错误引起");
+    }
+
+    //发送消息,不直接调用些方法,调用TcpClient中的发送消息
+    public void sendMsg(String msg){
+        if (ctx==null){
+            System.out.println("ctx is null");
+            try {
+                Thread.sleep(1000);
+                sendMsg(msg);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+            return;
+        }
+        ctx.writeAndFlush(Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));
+    }
+
+    //已经连接上,中途失去连接时的处理
+    private void reConnect(final ChannelHandlerContext ctx){
+        totalRetryTimes++;
+        System.out.println("总计连接次数:"+totalRetryTimes);
+        if (totalRetryTimes>100){
+            //todo: 存储数据库,并告警
+        }
+        if (connected){
+            return;
+        }
+        retryTimes++;
+        if (retryTimes>3){
+            //超时3次,其它处理
+            System.out.println("重新连接"+(retryTimes-1)+"次,结束");
+            retryTimes = 0;
+            //todo: 从API获取新的serverIP和serverPort,全新连接
+            //TcpClient.getInstance().init();
+            return;
+        }
+
+        ctx.channel().eventLoop().schedule(new Runnable() {
+            @Override
+            public void run() {
+                System.out.println("重新连接,第"+retryTimes+"次");
+                TcpClient.getInstance().doConnect();
+                reConnect(ctx);
+            }
+        },retrySeconds*retryTimes, TimeUnit.SECONDS);
+    }
+}

+ 4 - 0
extra/build.gradle

@@ -107,6 +107,7 @@ dependencies {
      *  constraint-layout布局依赖
      */
     compile 'com.android.support.constraint:constraint-layout:1.1.0-beta5'
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
 
 }
 
@@ -121,4 +122,7 @@ if(componentTag){
         aspectExcludeJarFilter 'com.enation.geamtear.pay','AlipaySdk'
     }
 }
+repositories {
+    mavenCentral()
+}
 

+ 1 - 1
gradle.properties

@@ -13,7 +13,7 @@
 # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
 # org.gradle.parallel=true
 #Wed Sep 27 17:07:24 CST 2017
-systemProp.http.proxyHost=mirrors.neusoft.edu.cn
+#systemProp.http.proxyHost=mirrors.neusoft.edu.cn
 org.gradle.jvmargs=-XX\:MaxHeapSize\=4096m -Xmx4096m
 systemProp.http.proxyPort=80
 org.gradle.daemon=true

+ 4 - 0
hello/build.gradle

@@ -105,6 +105,7 @@ dependencies {
      *  constraint-layout布局依赖
      */
     compile 'com.android.support.constraint:constraint-layout:1.1.0-beta5'
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
 }
 
 /**
@@ -118,3 +119,6 @@ if(componentTag){
         aspectExcludeJarFilter 'com.enation.geamtear.pay','AlipaySdk'
     }
 }
+repositories {
+    mavenCentral()
+}

+ 3 - 0
hello/src/main/java/com/wdkl/ncs/android/component/hello/activity/HelloListActivity.kt

@@ -82,6 +82,9 @@ class HelloListActivity : BaseActivity<HelloListActivityPresenter, HelloListActL
             page += 1
             presenter.loadData(keyword,page)
         }
+        refresh.setOnRefreshListener{
+            presenter.loadData(keyword,1)
+        }
 //        adapter.setOnItemClickListener { data, _ ->
 //            push("/shop/detail",{postcard ->
 //                postcard.withInt("shopId", data.shopId)

+ 4 - 0
home/build.gradle

@@ -109,6 +109,7 @@ dependencies {
      *  constraint-layout布局依赖
      */
     compile 'com.android.support.constraint:constraint-layout:1.1.0-beta5'
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
 }
 
 /**
@@ -122,3 +123,6 @@ if(componentTag){
         aspectExcludeJarFilter 'com.enation.geamtear.pay','AlipaySdk'
     }
 }
+repositories {
+    mavenCentral()
+}

+ 4 - 0
middleware/build.gradle

@@ -75,4 +75,8 @@ dependencies {
 
     compile 'com.fasterxml.jackson.core:jackson-databind:2.9.5'
     compile 'io.swagger:swagger-annotations:1.5.14'
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+}
+repositories {
+    mavenCentral()
 }

+ 4 - 0
setting/build.gradle

@@ -107,6 +107,7 @@ dependencies {
      *  constraint-layout布局依赖
      */
     compile 'com.android.support.constraint:constraint-layout:1.1.0-beta5'
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
 
 }
 
@@ -121,3 +122,6 @@ if(componentTag){
         aspectExcludeJarFilter 'com.enation.geamtear.pay','AlipaySdk'
     }
 }
+repositories {
+    mavenCentral()
+}

+ 4 - 0
shop/build.gradle

@@ -107,6 +107,7 @@ dependencies {
      *  constraint-layout布局依赖
      */
     compile 'com.android.support.constraint:constraint-layout:1.1.0-beta5'
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
 
 }
 
@@ -121,3 +122,6 @@ if(componentTag){
         aspectExcludeJarFilter 'com.enation.geamtear.pay','AlipaySdk'
     }
 }
+repositories {
+    mavenCentral()
+}

+ 4 - 0
welcome/build.gradle

@@ -102,6 +102,7 @@ dependencies {
      * 路由注解处理器
      */
     kapt "com.enation.geamtear:jrouter-compiler:$router_version"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
 
 }
 
@@ -115,4 +116,7 @@ if(componentTag){
          */
         aspectExcludeJarFilter 'com.enation.geamtear.pay','AlipaySdk'
     }
+}
+repositories {
+    mavenCentral()
 }