├── sample
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── styles.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── dimens.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── layout
│ │ │ │ ├── include_divider.xml
│ │ │ │ ├── activity_multicast_server.xml
│ │ │ │ ├── activity_mina_tcp_server.xml
│ │ │ │ ├── activity_multicast_client.xml
│ │ │ │ ├── activity_mina_tcp_client.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ └── activity_home.xml
│ │ │ └── values-w820dp
│ │ │ │ └── dimens.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── ethanco
│ │ │ │ └── sample
│ │ │ │ ├── TestBean.java
│ │ │ │ ├── ScrollBottomTextWatcher.java
│ │ │ │ ├── HomeActivity.java
│ │ │ │ ├── MinaTcpServerActivity.java
│ │ │ │ ├── MulticastServerActivity.java
│ │ │ │ ├── MinaUdpServerActivity.java
│ │ │ │ ├── MulticastClientActivity.java
│ │ │ │ ├── MinaTcpServerByteActivity.java
│ │ │ │ ├── MinaTcpServerHeartBeatActivity.java
│ │ │ │ ├── MinaTcpClientActivity.java
│ │ │ │ ├── UdpClientActivity.java
│ │ │ │ ├── MinaUdpClientActivity.java
│ │ │ │ ├── MinaTcpClientByteActivity.java
│ │ │ │ └── MinaTcpClientHeartBeatActivity.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── ethanco
│ │ │ └── sample
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── ethanco
│ │ └── sample
│ │ └── ApplicationTest.java
├── proguard-rules.pro
└── build.gradle
├── halo-turbo
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── ethanco
│ │ │ │ └── halo
│ │ │ │ └── turbo
│ │ │ │ ├── ads
│ │ │ │ ├── AbstractHalo.java
│ │ │ │ ├── ISession.java
│ │ │ │ ├── AbstractSession.java
│ │ │ │ ├── AbstractLog.java
│ │ │ │ ├── ISocket.java
│ │ │ │ ├── IConvertor.java
│ │ │ │ ├── ILog.java
│ │ │ │ ├── IHandler.java
│ │ │ │ ├── IHandlerAdapter.java
│ │ │ │ ├── IKeepAliveListener.java
│ │ │ │ ├── BaseLogHandler.java
│ │ │ │ └── AbstractSocket.java
│ │ │ │ ├── type
│ │ │ │ └── Mode.java
│ │ │ │ ├── impl
│ │ │ │ ├── handler
│ │ │ │ │ ├── EmptyHandler.java
│ │ │ │ │ ├── HexLogHandler.java
│ │ │ │ │ └── StringLogHandler.java
│ │ │ │ ├── convert
│ │ │ │ │ ├── StringByteConvertor.java
│ │ │ │ │ ├── ObjectByteConvertor.java
│ │ │ │ │ └── ConvertManager.java
│ │ │ │ └── socket
│ │ │ │ │ ├── IHopeSocket.java
│ │ │ │ │ ├── UdpClientSocket.java
│ │ │ │ │ └── MulticastSocket.java
│ │ │ │ ├── bean
│ │ │ │ ├── Config.java
│ │ │ │ └── KeepAlive.java
│ │ │ │ ├── utils
│ │ │ │ ├── Util.java
│ │ │ │ └── HexUtil.java
│ │ │ │ ├── SocketFactory.java
│ │ │ │ └── Halo.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── ethanco
│ │ │ └── halo
│ │ │ └── turbo
│ │ │ ├── ExampleUnitTest.java
│ │ │ └── HaloTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── ethanco
│ │ └── halo
│ │ └── turbo
│ │ └── ApplicationTest.java
├── proguard-rules.pro
└── build.gradle
├── halo-turbo-mina
├── .gitignore
├── libs
│ ├── mina-core-2.0.16.jar
│ └── slf4j-android-1.6.1-RC1.jar
├── src
│ ├── main
│ │ ├── res
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── ethanco
│ │ │ └── halo
│ │ │ └── turbo
│ │ │ └── mina
│ │ │ ├── MinaTcpServerSocket.java
│ │ │ ├── MinaUdpServerSocket.java
│ │ │ ├── MinaUdpClientSocket.java
│ │ │ └── MinaTcpClientSocket.java
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── ethanco
│ │ │ └── halo
│ │ │ └── turbo
│ │ │ └── mina
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── ethanco
│ │ └── halo
│ │ └── turbo
│ │ └── mina
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── json-convertor
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── ethanco
│ │ │ └── json
│ │ │ └── convertor
│ │ │ └── convert
│ │ │ ├── ObjectJsonByteConvertor.java
│ │ │ └── ObjectJsonConvertor.java
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── ethanco
│ │ │ └── json
│ │ │ └── convertor
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── ethanco
│ │ └── json
│ │ └── convertor
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── .idea
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── vcs.xml
├── kotlinc.xml
├── runConfigurations.xml
├── compiler.xml
├── modules.xml
├── gradle.xml
└── misc.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── gradlew.bat
├── Mina Byte数组传输-ByteArrayCodecFactory
├── ReadMe.md
└── gradlew
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/halo-turbo/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/halo-turbo-mina/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/json-convertor/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':sample', ':halo-turbo', ':halo-turbo-mina', ':json-convertor'
2 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthanCo/Halo-Turbo/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/halo-turbo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Halo-Turbo
3 |
4 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Halo-Sample
3 |
4 |
--------------------------------------------------------------------------------
/halo-turbo-mina/libs/mina-core-2.0.16.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthanCo/Halo-Turbo/HEAD/halo-turbo-mina/libs/mina-core-2.0.16.jar
--------------------------------------------------------------------------------
/halo-turbo-mina/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Halo-Turbo-Mina
3 |
4 |
--------------------------------------------------------------------------------
/json-convertor/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Json-Convertor
3 |
4 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthanCo/Halo-Turbo/HEAD/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthanCo/Halo-Turbo/HEAD/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/halo-turbo-mina/libs/slf4j-android-1.6.1-RC1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthanCo/Halo-Turbo/HEAD/halo-turbo-mina/libs/slf4j-android-1.6.1-RC1.jar
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthanCo/Halo-Turbo/HEAD/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthanCo/Halo-Turbo/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthanCo/Halo-Turbo/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/ads/AbstractHalo.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.ads;
2 |
3 | /**
4 | * Created by EthanCo on 2016/9/14.
5 | */
6 | public abstract class AbstractHalo implements ISocket {
7 | }
8 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/ads/ISession.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.ads;
2 |
3 | /**
4 | * @author EthanCo
5 | * @since 2017/1/17
6 | */
7 | public interface ISession {
8 | void write(Object message);
9 |
10 | void close();
11 | }
12 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Apr 06 15:41:38 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/include_divider.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/json-convertor/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/type/Mode.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.type;
2 |
3 | /**
4 | * Created by EthanCo on 2016/9/14.
5 | */
6 | public enum Mode {
7 | MINA_NIO_TCP_CLIENT,
8 | MINA_NIO_TCP_SERVER,
9 | MINA_NIO_UDP_CLIENT,
10 | MINA_NIO_UDP_SERVER,
11 | MULTICAST,
12 | UDP_CLIENT,
13 | }
14 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/impl/handler/EmptyHandler.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.impl.handler;
2 |
3 | import com.ethanco.halo.turbo.ads.IHandlerAdapter;
4 |
5 | /**
6 | * 空的Handler
7 | *
8 | * @author EthanCo
9 | * @since 2017/1/17
10 | */
11 |
12 | public class EmptyHandler extends IHandlerAdapter {
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/ads/AbstractSession.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.ads;
2 |
3 | /**
4 | * 回话 抽象类
5 | *
6 | * @author EthanCo
7 | * @since 2017/1/17
8 | */
9 |
10 | public abstract class AbstractSession implements ISession {
11 | //private final IHandler handler;
12 |
13 | public AbstractSession() {
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/sample/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/test/java/com/ethanco/sample/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/halo-turbo/src/test/java/com/ethanco/halo/turbo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/sample/src/androidTest/java/com/ethanco/sample/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/ads/AbstractLog.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.ads;
2 |
3 | /**
4 | * @author EthanCo
5 | * @since 2017/1/18
6 | */
7 |
8 | public abstract class AbstractLog implements ILog {
9 | protected String prefix = "";
10 |
11 | protected String getPrefix() {
12 | return prefix;
13 | }
14 |
15 | protected void setPrefix(String prefix) {
16 | this.prefix = prefix;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/ads/ISocket.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.ads;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Created by EthanCo on 2016/9/14.
7 | */
8 | public interface ISocket {
9 | boolean start();
10 |
11 | void stop();
12 |
13 | List getHandlers();
14 |
15 | void addHandler(IHandler handler);
16 |
17 | boolean removeHandler(IHandler handler);
18 |
19 | boolean isRunning();
20 | }
21 |
--------------------------------------------------------------------------------
/halo-turbo/src/androidTest/java/com/ethanco/halo/turbo/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/halo-turbo-mina/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/ads/IConvertor.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.ads;
2 |
3 | /**
4 | * 转换器
5 | *
6 | * @author EthanCo
7 | * @since 2017/1/20
8 | */
9 |
10 | public interface IConvertor {
11 | //发送时 是否处理
12 | boolean isSentHandler(Object message);
13 |
14 | //接收时 是否处理
15 | boolean isReceiveHandler(Object message);
16 |
17 | //发送时 转换
18 | Object sentConvert(Object message);
19 |
20 | //接收时 转换
21 | Object receiveConvert(Object message);
22 | }
23 |
--------------------------------------------------------------------------------
/json-convertor/src/test/java/com/ethanco/json/convertor/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.json.convertor;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/halo-turbo-mina/src/test/java/com/ethanco/halo/turbo/mina/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.mina;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/ads/ILog.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.ads;
2 |
3 | /**
4 | * Log接口
5 | *
6 | * @author EthanCo
7 | * @since 2017/1/18
8 | */
9 |
10 | public interface ILog extends IHandler {
11 | void onStarting();
12 |
13 | void onStartSuccess();
14 |
15 | void onStartFailed(Exception e);
16 |
17 | void onStopping();
18 |
19 | void onStopped();
20 |
21 | void onReceiveException(Exception e);
22 |
23 | void onReConnecting();
24 |
25 | void onReConnected();
26 |
27 | void onReConnectFailed(Exception e);
28 | }
29 |
--------------------------------------------------------------------------------
/json-convertor/src/main/java/com/ethanco/json/convertor/convert/ObjectJsonByteConvertor.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.json.convertor.convert;
2 |
3 | /**
4 | * 如果是Object对象,则先转换为json字符串后,再转换为byte[]
5 | *
6 | * @author EthanCo
7 | * @since 2017/1/20
8 | */
9 |
10 | public class ObjectJsonByteConvertor extends ObjectJsonConvertor {
11 | @Override
12 | public Object sentConvert(Object message) {
13 | Object result = super.sentConvert(message);
14 | if (result instanceof String) {
15 | return ((String) result).getBytes();
16 | }
17 | return result;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/ads/IHandler.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.ads;
2 |
3 | /**
4 | * 回调处理类
5 | *
6 | * @author EthanCo
7 | * @since 2017/1/17
8 | */
9 |
10 | public interface IHandler {
11 | //会话(session)创建之后,回调该方法
12 | void sessionCreated(ISession session);
13 |
14 | //会话(session)打开之后,回调该方法
15 | void sessionOpened(ISession session);
16 |
17 | //会话(session)关闭后,回调该方法
18 | void sessionClosed(ISession session);
19 |
20 | //接收到消息时回调这个方法
21 | void messageReceived(ISession session, Object message);
22 |
23 | //发送数据时回调这个方法
24 | void messageSent(ISession session, Object message);
25 | }
26 |
--------------------------------------------------------------------------------
/sample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\SDK/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/halo-turbo/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\SDK/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/halo-turbo-mina/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Java\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/json-convertor/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Java\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/ads/IHandlerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.ads;
2 |
3 | /**
4 | * Handler 默认实现
5 | *
6 | * @author EthanCo
7 | * @since 2017/1/18
8 | */
9 |
10 | public abstract class IHandlerAdapter implements IHandler {
11 |
12 | @Override
13 | public void sessionCreated(ISession session) {
14 |
15 | }
16 |
17 | @Override
18 | public void sessionOpened(ISession session) {
19 |
20 | }
21 |
22 | @Override
23 | public void sessionClosed(ISession session) {
24 |
25 | }
26 |
27 | @Override
28 | public void messageReceived(ISession session, Object message) {
29 |
30 | }
31 |
32 | @Override
33 | public void messageSent(ISession session, Object message) {
34 |
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | <<<<<<< HEAD
2 | *.iml
3 | .gradle
4 | /local.properties
5 | /.idea/workspace.xml
6 | /.idea/libraries
7 | .DS_Store
8 | /build
9 | /captures
10 | =======
11 | # Built application files
12 | *.apk
13 | *.ap_
14 |
15 | # Files for the ART/Dalvik VM
16 | *.dex
17 |
18 | # Java class files
19 | *.class
20 |
21 | # Generated files
22 | bin/
23 | gen/
24 | out/
25 |
26 | # Gradle files
27 | .gradle/
28 | build/
29 |
30 | # Local configuration file (sdk path, etc)
31 | local.properties
32 |
33 | # Proguard folder generated by Eclipse
34 | proguard/
35 |
36 | # Log Files
37 | *.log
38 |
39 | # Android Studio Navigation editor temp files
40 | .navigation/
41 |
42 | # Android Studio captures folder
43 | captures/
44 |
45 | # Intellij
46 | *.iml
47 | .idea/workspace.xml
48 |
49 | # Keystore files
50 | *.jks
51 | >>>>>>> 270eb2d3bbc73ca31a11c299773d32e874b7153c
52 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion '25.0.0'
6 |
7 | defaultConfig {
8 | applicationId "com.ethanco.sample"
9 | minSdkVersion 15
10 | targetSdkVersion 24
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | dataBinding {
21 | enabled true
22 | }
23 | }
24 |
25 | dependencies {
26 | compile fileTree(include: ['*.jar'], dir: 'libs')
27 | testCompile 'junit:junit:4.12'
28 | compile 'com.android.support:appcompat-v7:24.1.1'
29 | compile project(':halo-turbo')
30 | compile project(':halo-turbo-mina')
31 | compile project(':json-convertor')
32 | }
33 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/impl/convert/StringByteConvertor.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.impl.convert;
2 |
3 | import com.ethanco.halo.turbo.ads.IConvertor;
4 |
5 | /**
6 | * String转化为Byte[]
7 | *
8 | * @author EthanCo
9 | * @since 2017/1/20
10 | */
11 |
12 | public class StringByteConvertor implements IConvertor {
13 | @Override
14 | public boolean isSentHandler(Object message) {
15 | return message instanceof String;
16 | }
17 |
18 | @Override
19 | public boolean isReceiveHandler(Object message) {
20 | return message instanceof byte[] || message instanceof Byte[];
21 | }
22 |
23 | @Override
24 | public Object sentConvert(Object message) {
25 | return ((String) message).getBytes();
26 | }
27 |
28 | @Override
29 | public Object receiveConvert(Object message) {
30 | return new String((byte[]) message).trim();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/json-convertor/src/androidTest/java/com/ethanco/json/convertor/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.json.convertor;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.ethanco.json.convertor.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/ethanco/sample/TestBean.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | /**
4 | * TODO
5 | *
6 | * @author EthanCo
7 | * @since 2017/1/22
8 | */
9 |
10 | public class TestBean {
11 | private String arg1;
12 | private String arg2;
13 |
14 | public TestBean(String arg1, String arg2) {
15 | this.arg1 = arg1;
16 | this.arg2 = arg2;
17 | }
18 |
19 | public String getArg1() {
20 | return arg1;
21 | }
22 |
23 | public void setArg1(String arg1) {
24 | this.arg1 = arg1;
25 | }
26 |
27 | public String getArg2() {
28 | return arg2;
29 | }
30 |
31 | public void setArg2(String arg2) {
32 | this.arg2 = arg2;
33 | }
34 |
35 | @Override
36 | public String toString() {
37 | return "TestBean{" +
38 | "arg1='" + arg1 + '\'' +
39 | ", arg2='" + arg2 + '\'' +
40 | '}';
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/halo-turbo-mina/src/androidTest/java/com/ethanco/halo/turbo/mina/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.mina;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.ethanco.halo.turbo.mina.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/bean/Config.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.bean;
2 |
3 | import android.content.Context;
4 |
5 | import com.ethanco.halo.turbo.ads.IConvertor;
6 | import com.ethanco.halo.turbo.ads.IHandler;
7 | import com.ethanco.halo.turbo.type.Mode;
8 |
9 | import java.util.List;
10 | import java.util.concurrent.ExecutorService;
11 |
12 | /**
13 | * Created by EthanCo on 2016/9/16.
14 | */
15 | public class Config {
16 | //模式
17 | public Mode mode;
18 | //目标IP
19 | public String targetIP;
20 | //目标端口
21 | public int targetPort;
22 | //源IP
23 | //public String sourceIP;
24 | //源端口
25 | public int sourcePort;
26 | //缓存大小
27 | public int bufferSize;
28 | //线程池
29 | public ExecutorService threadPool;
30 |
31 | public List handlers;
32 |
33 | public List convertors;
34 |
35 | public Object codec;
36 |
37 | public Context context;
38 |
39 | public KeepAlive keepAlive;
40 | }
41 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/impl/convert/ObjectByteConvertor.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.impl.convert;
2 |
3 | import com.ethanco.halo.turbo.ads.IConvertor;
4 |
5 | /**
6 | * Object转换为Byte[]
7 | *
8 | * @author EthanCo
9 | * @since 2017/1/20
10 | */
11 |
12 | public class ObjectByteConvertor implements IConvertor {
13 | @Override
14 | public boolean isSentHandler(Object message) {
15 | return message instanceof Object;
16 | }
17 |
18 | @Override
19 | public boolean isReceiveHandler(Object message) {
20 | return message instanceof byte[] || message instanceof Byte[];
21 | }
22 |
23 | @Override
24 | public Object sentConvert(Object message) {
25 | return message.toString().getBytes();
26 | }
27 |
28 | @Override
29 | public Object receiveConvert(Object message) {
30 | if (message instanceof String) {
31 | ((String) message).trim();
32 | }
33 | return message;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/impl/handler/HexLogHandler.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.impl.handler;
2 |
3 | import com.ethanco.halo.turbo.ads.BaseLogHandler;
4 | import com.ethanco.halo.turbo.utils.HexUtil;
5 |
6 | /**
7 | * 16进制 日志处理
8 | *
9 | * @author EthanCo
10 | * @since 2017/1/18
11 | */
12 |
13 | public class HexLogHandler extends BaseLogHandler {
14 |
15 | public HexLogHandler() {
16 | }
17 |
18 | public HexLogHandler(String tag) {
19 | super(tag);
20 | }
21 |
22 | @Override
23 | protected String convertToString(Object message) {
24 | if (message == null) {
25 | return "message is null";
26 | }
27 |
28 | String receive;
29 | if (message instanceof byte[] || message instanceof Byte[]) {
30 | receive = HexUtil.bytesToHexString((byte[]) message);
31 | } else if (message instanceof String) {
32 | receive = (String) message;
33 | } else {
34 | receive = message.toString();
35 | }
36 | return receive.trim();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/halo-turbo-mina/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 |
4 | group='com.github.EthanCo'
5 |
6 | android {
7 | compileSdkVersion 25
8 | buildToolsVersion "25.0.1"
9 |
10 | defaultConfig {
11 | minSdkVersion 15
12 | targetSdkVersion 25
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
17 |
18 | }
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | }
26 |
27 | dependencies {
28 | compile fileTree(include: ['*.jar'], dir: 'libs')
29 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
30 | exclude group: 'com.android.support', module: 'support-annotations'
31 | })
32 | compile 'com.android.support:appcompat-v7:25.0.1'
33 | testCompile 'junit:junit:4.12'
34 | compile project(':halo-turbo')
35 | }
36 |
--------------------------------------------------------------------------------
/halo-turbo/src/test/java/com/ethanco/halo/turbo/HaloTest.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo;
2 |
3 | import com.ethanco.halo.turbo.type.Mode;
4 |
5 | import org.junit.Before;
6 | import org.junit.Test;
7 | import org.robolectric.annotation.Config;
8 |
9 | import java.io.IOException;
10 |
11 | /**
12 | * Created by EthanCo on 2016/9/14.
13 | */
14 | @Config(constants = BuildConfig.class, sdk = 21)
15 | public class HaloTest {
16 | private Halo halo;
17 |
18 | @Before
19 | public void setUp() {
20 |
21 | Halo.Builder builder = new Halo.Builder()
22 | .setTargetIP("192.168.2.1")
23 | .setTargetPort(8890)
24 | .setMode(Mode.MINA_NIO_TCP_CLIENT)
25 | //.setType(Type.UDP)
26 | .setBufferSize(1024 * 2);
27 |
28 | halo = builder.build();
29 | }
30 |
31 | @Test
32 | public void testLogic() {
33 | try {
34 | halo.start();
35 | } catch (IOException e) {
36 | e.printStackTrace();
37 | }
38 | //halo.send("hello");
39 | halo.stop();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/json-convertor/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 |
4 | group='com.github.EthanCo'
5 |
6 |
7 | android {
8 | compileSdkVersion 25
9 | buildToolsVersion "25.0.1"
10 |
11 | defaultConfig {
12 | minSdkVersion 15
13 | targetSdkVersion 25
14 | versionCode 1
15 | versionName "1.0"
16 |
17 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
18 |
19 | }
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | }
27 |
28 | dependencies {
29 | compile fileTree(dir: 'libs', include: ['*.jar'])
30 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
31 | exclude group: 'com.android.support', module: 'support-annotations'
32 | })
33 | compile 'com.android.support:appcompat-v7:25.0.1'
34 | testCompile 'junit:junit:4.12'
35 | compile project(':halo-turbo')
36 | compile 'com.google.code.gson:gson:2.8.0'
37 | }
38 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | #3F51B5
6 |
7 | #303F9F
8 |
9 | #1976D2
10 |
11 | #DD0050
12 |
13 | #C60037
14 |
15 | #212121
16 |
17 | #757575
18 |
19 | #d5d5d5
20 |
21 | #FFFFFF
22 |
23 | #BDBDBD
24 |
25 |
26 | #FFFFFF
27 |
28 | #000000
29 |
30 | #F5F5F5
31 |
32 | #00000000
33 |
34 |
--------------------------------------------------------------------------------
/halo-turbo/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 |
4 | group='com.github.EthanCo'
5 |
6 | android {
7 | compileSdkVersion 24
8 | buildToolsVersion '25.0.0'
9 |
10 | defaultConfig {
11 | minSdkVersion 15
12 | targetSdkVersion 24
13 | versionCode 1
14 | versionName "1.0"
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | configurations.all {
23 | resolutionStrategy {
24 | force 'com.android.support:support-annotations:23.2.1'
25 | }
26 | }
27 | }
28 |
29 | dependencies {
30 | compile fileTree(dir: 'libs', include: ['*.jar'])
31 | testCompile 'junit:junit:4.12'
32 | //Mockito
33 | testCompile 'org.mockito:mockito-all:2.0.2-beta'
34 | //Robolectric
35 | testCompile 'org.robolectric:robolectric:3.1.2'
36 | testCompile 'org.khronos:opengl-api:gl1.1-android-2.1_r1'
37 | testCompile 'org.hamcrest:hamcrest-all:1.3'
38 |
39 | compile 'com.android.support:appcompat-v7:24.1.1'
40 | }
41 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/ads/IKeepAliveListener.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.ads;
2 |
3 | import com.ethanco.halo.turbo.bean.KeepAlive;
4 |
5 | /**
6 | * 心跳 回调
7 | *
8 | * @author EthanCo
9 | * @since 2017/7/31
10 | * - ┌─┐ ┌─┐
11 | * - ┌──┘ ┴───────┘ ┴──┐
12 | * - │ │
13 | * - │ ─── │
14 | * - │ ─┬┘ └┬─ │
15 | * - │ │
16 | * - │ ─┴─ │
17 | * - │ │
18 | * - └───┐ ┌───┘
19 | * - │ │
20 | * - │ │
21 | * - │ │
22 | * - │ └──────────────┐
23 | * - │ │
24 | * - │ ├─┐
25 | * - │ ┌─┘
26 | * - │ │
27 | * - └─┐ ┐ ┌───────┬──┐ ┌──┘
28 | * - │ ─┤ ─┤ │ ─┤ ─┤
29 | * - └──┴──┘ └──┴──┘
30 | * --------------- 神兽保佑 ---------------
31 | * --------------- 永无BUG! ---------------
32 | */
33 |
34 | public interface IKeepAliveListener {
35 | void onKeepAliveRequestTimedOut(KeepAlive keepAlive, ISession iSession);
36 |
37 | boolean isKeepAliveMessage(ISession ioSession, Object message);
38 |
39 | Object getKeepAliveMessage(ISession ioSession, Object o);
40 | }
41 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/ethanco/sample/ScrollBottomTextWatcher.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 | import android.text.Editable;
6 | import android.text.TextWatcher;
7 | import android.widget.ScrollView;
8 |
9 | import java.lang.ref.WeakReference;
10 |
11 | /**
12 | * ScrollView 总是滑动到底部
13 | *
14 | * @author EthanCo
15 | * @since 2017/1/24
16 | */
17 |
18 | public class ScrollBottomTextWatcher implements TextWatcher {
19 |
20 | private WeakReference scrollViewRef;
21 |
22 | public ScrollBottomTextWatcher(ScrollView scrollView) {
23 | this.scrollViewRef = new WeakReference(scrollView);
24 | }
25 |
26 | @Override
27 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {
28 |
29 | }
30 |
31 | @Override
32 | public void onTextChanged(CharSequence s, int start, int before, int count) {
33 |
34 | }
35 |
36 | @Override
37 | public void afterTextChanged(Editable s) {
38 | final ScrollView scrollview = scrollViewRef.get();
39 | if (scrollview == null) {
40 | return;
41 | }
42 |
43 | new Handler(Looper.getMainLooper()).post(new Runnable() {
44 | @Override
45 | public void run() {
46 | scrollview.fullScroll(ScrollView.FOCUS_DOWN);
47 | }
48 | });
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/json-convertor/src/main/java/com/ethanco/json/convertor/convert/ObjectJsonConvertor.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.json.convertor.convert;
2 |
3 | import com.ethanco.halo.turbo.ads.IConvertor;
4 | import com.google.gson.Gson;
5 |
6 | /**
7 | * @author EthanCo
8 | * @since 2017/1/20
9 | */
10 |
11 | public class ObjectJsonConvertor implements IConvertor {
12 | private Gson gson = new Gson();
13 |
14 | @Override
15 | public boolean isSentHandler(Object message) {
16 | return message instanceof Object;
17 | }
18 |
19 | @Override
20 | public boolean isReceiveHandler(Object message) {
21 | return message instanceof Object;
22 | }
23 |
24 | @Override
25 | public Object sentConvert(Object message) {
26 | if (message instanceof String || message instanceof Byte[] || message instanceof byte[]) {
27 | return message;
28 | }
29 |
30 | String json = gson.toJson(message);
31 | //Log.i("Z-Test", "sentConvert:" + json);
32 | return json;
33 | }
34 |
35 | @Override
36 | public Object receiveConvert(Object message) {
37 | return message;
38 | /*if (message instanceof byte[] || message instanceof Byte[]) {
39 | return message;//new String((byte[]) message).trim();
40 | } else if (message instanceof String) {
41 | return message;//((String) (message)).trim();
42 | }
43 | return message;*/
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_multicast_server.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
18 |
19 |
23 |
24 |
25 |
26 |
31 |
32 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/impl/handler/StringLogHandler.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.impl.handler;
2 |
3 | import com.ethanco.halo.turbo.ads.BaseLogHandler;
4 | import com.ethanco.halo.turbo.ads.ISession;
5 |
6 | /**
7 | * 默认日志处理
8 | *
9 | * @author EthanCo
10 | * @since 2017/1/18
11 | */
12 |
13 | public class StringLogHandler extends BaseLogHandler {
14 |
15 | public StringLogHandler() {
16 | }
17 |
18 | public StringLogHandler(String tag) {
19 | super(tag);
20 | }
21 |
22 | @Override
23 | public void messageReceived(ISession session, Object message) {
24 | String receive = convertToString(message);
25 | printLog("messageReceived:" + receive);
26 | }
27 |
28 | @Override
29 | public void messageSent(ISession session, Object message) {
30 | String sendData = convertToString(message);
31 | printLog("messageSent:" + sendData);
32 | }
33 |
34 | @Override
35 | protected String convertToString(Object message) {
36 | if (message == null) {
37 | return "message is null";
38 | }
39 |
40 | String receive;
41 | if (message instanceof byte[]) {
42 | receive = new String((byte[]) message);
43 | } else if (message instanceof String) {
44 | receive = (String) message;
45 | } else {
46 | receive = message.toString();
47 | }
48 | return receive.trim();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_mina_tcp_server.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
18 |
19 |
23 |
24 |
25 |
26 |
31 |
32 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/impl/convert/ConvertManager.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.impl.convert;
2 |
3 | import com.ethanco.halo.turbo.ads.IConvertor;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * IConvertor 管理类
9 | *
10 | * @author EthanCo
11 | * @since 2017/1/20
12 | */
13 | public class ConvertManager {
14 | List convertChain;
15 |
16 | public ConvertManager(List convertChain) {
17 | this.convertChain = convertChain;
18 | }
19 |
20 | public void add(IConvertor convertor) {
21 | if (convertChain == null) {
22 | return;
23 | }
24 | if (!convertChain.contains(convertor)) {
25 | convertChain.add(convertor);
26 | }
27 | }
28 |
29 | public void remove(IConvertor convertor) {
30 | if (convertChain == null) {
31 | return;
32 | }
33 |
34 | convertChain.remove(convertor);
35 | }
36 |
37 | public Object convert(Object message) {
38 | if (convertChain == null) {
39 | return message;
40 | }
41 |
42 | for (IConvertor convertor : convertChain) {
43 | if (convertor.isSentHandler(message)) {
44 | return convertor.sentConvert(message);
45 | }
46 | }
47 |
48 | return message;
49 | }
50 |
51 | public Object receive(Object message) {
52 | if (convertChain == null) {
53 | return message;
54 | }
55 |
56 | for (IConvertor convertor : convertChain) {
57 | return convertor.receiveConvert(message);
58 | }
59 |
60 | return message;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_multicast_client.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
18 |
19 |
23 |
24 |
25 |
26 |
31 |
32 |
37 |
38 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 40dip
6 |
7 |
8 | 32sp
9 | 45sp
10 | 56sp
11 | 112sp
12 |
13 |
14 | 24sp
15 | 22sp
16 |
17 |
18 | 20sp
19 |
20 |
21 | 18sp
22 | 16sp
23 |
24 |
25 | 14sp
26 |
27 |
28 | 12sp
29 |
30 |
31 |
32 | 16dp
33 |
34 | 48dp
35 |
36 | 8dp
37 |
38 | 8dp
39 |
40 | 16dp
41 |
42 | 64dp
43 | 48dp
44 |
45 | 48dp
46 | 5dp
47 |
48 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/utils/Util.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.utils;
2 |
3 | import java.net.Inet4Address;
4 | import java.net.InetAddress;
5 | import java.net.NetworkInterface;
6 | import java.net.SocketException;
7 | import java.util.Enumeration;
8 |
9 | /**
10 | * Created by EthanCo on 2016/9/14.
11 | */
12 | public class Util {
13 | public static String HALO = "halo";
14 |
15 | public static void println(String tag, String message) {
16 | System.out.println(tag + ": " + message);
17 | }
18 |
19 | public static void println(String message) {
20 | println("ethanco", message);
21 | }
22 |
23 | /**
24 | * 获取本地地址
25 | *
26 | * @return bytes
27 | */
28 | public static byte[] getLocalIP() {
29 | try {
30 | for (Enumeration mEnumeration = NetworkInterface
31 | .getNetworkInterfaces(); mEnumeration.hasMoreElements(); ) {
32 |
33 | NetworkInterface intf = mEnumeration.nextElement();
34 |
35 | for (Enumeration enumIPAddress = intf
36 | .getInetAddresses(); enumIPAddress.hasMoreElements(); ) {
37 | InetAddress inetAddress = enumIPAddress.nextElement();
38 |
39 | // 如果不是回环地址
40 | if (!inetAddress.isLoopbackAddress() && Inet4Address.class.isInstance(inetAddress)) {
41 |
42 | // 直接返回本地IP地址
43 | return inetAddress.getAddress();
44 | }
45 | }
46 | }
47 | } catch (SocketException ex) {
48 | System.err.print("error");
49 | }
50 | return new byte[4];
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_mina_tcp_client.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
17 |
18 |
22 |
23 |
24 |
25 |
31 |
32 |
37 |
38 |
43 |
44 |
50 |
51 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/SocketFactory.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo;
2 |
3 | import com.ethanco.halo.turbo.ads.ISocket;
4 | import com.ethanco.halo.turbo.bean.Config;
5 | import com.ethanco.halo.turbo.impl.socket.MulticastSocket;
6 | import com.ethanco.halo.turbo.impl.socket.UdpClientSocket;
7 | import com.ethanco.halo.turbo.type.Mode;
8 |
9 | import java.lang.reflect.Constructor;
10 | import java.lang.reflect.InvocationTargetException;
11 |
12 | /**
13 | * Created by EthanCo on 2016/9/19.
14 | */
15 | class SocketFactory {
16 |
17 | public static ISocket create(Config config) {
18 | ISocket haloImpl;
19 | Mode mode = config.mode;
20 |
21 | if (mode == Mode.MULTICAST) {
22 | haloImpl = new MulticastSocket(config);
23 | } else if(mode == Mode.UDP_CLIENT){
24 | haloImpl = new UdpClientSocket(config);
25 | } else {
26 | haloImpl = createByReflect(mode, config);
27 | }
28 | return haloImpl;
29 | }
30 |
31 | private static ISocket createByReflect(Mode mode, Config config) {
32 | String className;
33 | if (mode == Mode.MINA_NIO_TCP_CLIENT) {
34 | className = "com.ethanco.halo.turbo.mina.MinaTcpClientSocket";
35 | } else if (mode == Mode.MINA_NIO_TCP_SERVER) {
36 | className = "com.ethanco.halo.turbo.mina.MinaTcpServerSocket";
37 | } else if (mode == Mode.MINA_NIO_UDP_CLIENT) {
38 | className = "com.ethanco.halo.turbo.mina.MinaUdpClientSocket";
39 | } else if (mode == Mode.MINA_NIO_UDP_SERVER) {
40 | className = "com.ethanco.halo.turbo.mina.MinaUdpServerSocket";
41 | } else {
42 | return null;
43 | }
44 |
45 | ISocket haloImpl = null;
46 | try {
47 | Class cls = Class.forName(className);
48 | Constructor constructor = cls.getConstructor(Config.class);
49 | haloImpl = (ISocket) constructor.newInstance(config);
50 | } catch (ClassNotFoundException e) {
51 | e.printStackTrace();
52 | } catch (NoSuchMethodException e) {
53 | e.printStackTrace();
54 | } catch (IllegalAccessException e) {
55 | e.printStackTrace();
56 | } catch (InstantiationException e) {
57 | e.printStackTrace();
58 | } catch (InvocationTargetException e) {
59 | e.printStackTrace();
60 | }
61 | return haloImpl;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/bean/KeepAlive.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.bean;
2 |
3 | import com.ethanco.halo.turbo.ads.IKeepAliveListener;
4 |
5 | /**
6 | * 心跳
7 | *
8 | * @author EthanCo
9 | * @since 2017/7/31
10 | * - ┌─┐ ┌─┐
11 | * - ┌──┘ ┴───────┘ ┴──┐
12 | * - │ │
13 | * - │ ─── │
14 | * - │ ─┬┘ └┬─ │
15 | * - │ │
16 | * - │ ─┴─ │
17 | * - │ │
18 | * - └───┐ ┌───┘
19 | * - │ │
20 | * - │ │
21 | * - │ │
22 | * - │ └──────────────┐
23 | * - │ │
24 | * - │ ├─┐
25 | * - │ ┌─┘
26 | * - │ │
27 | * - └─┐ ┐ ┌───────┬──┐ ┌──┘
28 | * - │ ─┤ ─┤ │ ─┤ ─┤
29 | * - └──┴──┘ └──┴──┘
30 | * --------------- 神兽保佑 ---------------
31 | * --------------- 永无BUG! ---------------
32 | */
33 |
34 | public class KeepAlive {
35 | private int interval; //心跳间隔时间
36 | private int timeout; //心跳超时时间
37 | private int reConnTime = 60 * 1000; //重连时间
38 | private IKeepAliveListener keepAliveListener;
39 |
40 | public KeepAlive(int interval, int timeout, IKeepAliveListener keepAliveListener) {
41 | this.interval = interval;
42 | this.timeout = timeout;
43 | this.keepAliveListener = keepAliveListener;
44 | }
45 |
46 | public KeepAlive(int interval, int timeout, int reConnTime, IKeepAliveListener keepAliveListener) {
47 | this.interval = interval;
48 | this.timeout = timeout;
49 | this.reConnTime = reConnTime;
50 | this.keepAliveListener = keepAliveListener;
51 | }
52 |
53 | public int getInterval() {
54 | return interval;
55 | }
56 |
57 | public void setInterval(int interval) {
58 | this.interval = interval;
59 | }
60 |
61 | public int getTimeout() {
62 | return timeout;
63 | }
64 |
65 | public void setTimeout(int timeout) {
66 | this.timeout = timeout;
67 | }
68 |
69 | public int getReConnTime() {
70 | return reConnTime;
71 | }
72 |
73 | public void setReConnTime(int reConnTime) {
74 | this.reConnTime = reConnTime;
75 | }
76 |
77 | public IKeepAliveListener getKeepAliveListener() {
78 | return keepAliveListener;
79 | }
80 |
81 | public void setKeepAliveListener(IKeepAliveListener keepAliveListener) {
82 | this.keepAliveListener = keepAliveListener;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/Mina Byte数组传输-ByteArrayCodecFactory:
--------------------------------------------------------------------------------
1 | public class ByteArrayCodecFactory implements ProtocolCodecFactory {
2 | private ByteArrayDecoder decoder;
3 | private ByteArrayEncoder encoder;
4 |
5 | public ByteArrayCodecFactory() {
6 | encoder = new ByteArrayEncoder();
7 | decoder = new ByteArrayDecoder();
8 | }
9 |
10 | @Override
11 | public ProtocolEncoder getEncoder(IoSession ioSession) throws Exception {
12 | return encoder;
13 | }
14 |
15 | @Override
16 | public ProtocolDecoder getDecoder(IoSession ioSession) throws Exception {
17 | return decoder;
18 | }
19 |
20 | //解码
21 | private class ByteArrayDecoder extends CumulativeProtocolDecoder {
22 |
23 |
24 | @Override
25 | protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
26 | if (in.remaining() > 6) {//有数据时,读取前8字节判断消息长度
27 |
28 | byte[] sizeBytes = new byte[7];
29 |
30 | in.mark();//标记当前位置,以便reset
31 |
32 | //因为我的前数据包的长度是保存在第6-7字节中,
33 |
34 | in.get(sizeBytes, 0, 7);//读取4字节
35 |
36 | String strHead = bytesToString(sizeBytes,0,4);
37 | if (!"HOPE".equalsIgnoreCase(strHead)) {
38 | in.clear();
39 | return true;
40 | }
41 |
42 | int size = DataTypeUtil.getInt(sizeBytes, 5) + 7;
43 |
44 | in.reset();
45 |
46 | if (size > in.remaining()) {//如果消息内容不够,则重置,相当于不读取size
47 |
48 | return false;//父类接收新数据,以拼凑成完整数据
49 |
50 | } else {
51 |
52 | byte[] bytes = new byte[size];
53 |
54 | in.get(bytes, 0, size);
55 |
56 | //把字节转换为Java对象的工具类
57 | out.write(bytes);
58 |
59 | if (in.remaining() > 0) {//如果读取内容后还粘了包,就让父类再重读 一次,进行下一次解析
60 |
61 | return true;
62 |
63 | }
64 |
65 | }
66 |
67 | }
68 | return false;//处理成功,让父类进行接收下个包
69 | }
70 | }
71 |
72 | //编码
73 | private class ByteArrayEncoder extends ProtocolEncoderAdapter {
74 | @Override
75 | public void encode(IoSession session, Object message,
76 | ProtocolEncoderOutput out) {
77 | byte[] bytes = (byte[]) message;
78 |
79 | IoBuffer buffer = IoBuffer.allocate(256);
80 | buffer.setAutoExpand(true);
81 | buffer.put(bytes);
82 | buffer.flip();
83 | out.write(buffer);
84 | out.flush();
85 | buffer.free();
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/impl/socket/IHopeSocket.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.impl.socket;
2 |
3 | import java.net.InetAddress;
4 |
5 | /**
6 | * Created by hult on 2016/5/4.
7 | * Socket接口
8 | */
9 | public interface IHopeSocket {
10 |
11 | /**
12 | * 绑定本地地址端口
13 | *
14 | * @param port 端口
15 | */
16 | void bind(int port);
17 |
18 | /**
19 | * 绑定本地地址端口
20 | *
21 | * @param address 地址
22 | * @param port 端口
23 | */
24 | void bind(InetAddress address, int port);
25 |
26 | /**
27 | * 绑定本地地址端口
28 | *
29 | * @param address 地址
30 | * @param port 端口
31 | */
32 | void bind(String address, int port);
33 |
34 | /**
35 | * 连接
36 | *
37 | * @param address 地址
38 | * @param port 端口
39 | */
40 | void connect(InetAddress address, int port);
41 |
42 | /**
43 | * 连接
44 | *
45 | * @param address 地址
46 | * @param port 端口
47 | */
48 | void connect(String address, int port);
49 |
50 | /**
51 | * 断开连接
52 | */
53 | void disconnect();
54 |
55 | /**
56 | * receive data
57 | *
58 | * @param maxBufferSize 最大接收缓冲区大小
59 | * @return begin receive success ?
60 | */
61 | Boolean beginReceive(int maxBufferSize);
62 |
63 | /**
64 | * end receive
65 | */
66 | void endReceive();
67 |
68 | /**
69 | * send data
70 | *
71 | * @param buffer raw byte buffer
72 | * @param offset buffer offset
73 | * @param length send length
74 | */
75 | void send(byte[] buffer, int offset, int length);
76 |
77 | /**
78 | * send data
79 | *
80 | * @param buffer
81 | * @param offset
82 | * @param length
83 | * @param IP
84 | * @param port
85 | */
86 | void send(byte[] buffer, int offset, int length, String IP, int port);
87 |
88 | /**
89 | * 设置广播地址
90 | *
91 | * @param address IP地址
92 | * @param port 端口
93 | */
94 | void setBroadCastAddress(String address, int port);
95 |
96 | /**
97 | * UDP广播
98 | *
99 | * @param buffer raw byte buffer
100 | * @param offset buffer offset
101 | * @param length send length
102 | */
103 | void broadCast(byte[] buffer, int offset, int length);
104 |
105 | /**
106 | * 获取本地IP
107 | *
108 | * @return ip
109 | */
110 | byte[] getLocalIp();
111 |
112 | void setOnSocketErrorListener(OnSocketErrorListener errorListener);
113 |
114 | interface OnSocketErrorListener {
115 | void onSocketError(Exception e);
116 | }
117 | }
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/ads/BaseLogHandler.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.ads;
2 |
3 | import android.util.Log;
4 |
5 | import com.ethanco.halo.turbo.utils.Util;
6 |
7 | /**
8 | * 默认日志处理
9 | *
10 | * @author EthanCo
11 | * @since 2017/1/18
12 | */
13 |
14 | public abstract class BaseLogHandler extends AbstractLog {
15 | protected String tag = Util.HALO;
16 |
17 | public BaseLogHandler() {
18 | }
19 |
20 | public BaseLogHandler(String tag) {
21 | this.tag = tag;
22 | }
23 |
24 | @Override
25 | public void sessionCreated(ISession session) {
26 | printLog("sessionCreated");
27 | }
28 |
29 | @Override
30 | public void sessionOpened(ISession session) {
31 | printLog("sessionOpened");
32 | }
33 |
34 | @Override
35 | public void sessionClosed(ISession session) {
36 | printLog("sessionClosed");
37 | }
38 |
39 | @Override
40 | public void messageReceived(ISession session, Object message) {
41 | String receive = convertToString(message);
42 | printLog("messageReceived:" + receive);
43 | }
44 |
45 | @Override
46 | public void messageSent(ISession session, Object message) {
47 | String sendData = convertToString(message);
48 | printLog("messageSent:" + sendData);
49 | }
50 |
51 | protected abstract String convertToString(Object message);
52 |
53 | protected void printLog(String sessionCreated) {
54 | Log.i(tag, sessionCreated);
55 | }
56 |
57 | @Override
58 | public void onStarting() {
59 | printLog(getPrefix() + " onStarting");
60 | }
61 |
62 | @Override
63 | public void onStartSuccess() {
64 | printLog(getPrefix() + " onStartSuccess");
65 | }
66 |
67 | @Override
68 | public void onStartFailed(Exception e) {
69 | printLog(getPrefix() + " onStartFailed:" + e.getMessage());
70 | }
71 |
72 | @Override
73 | public void onStopping() {
74 | printLog(getPrefix() + " onStopping");
75 | }
76 |
77 | @Override
78 | public void onStopped() {
79 | printLog(getPrefix() + " onStopped");
80 | }
81 |
82 | @Override
83 | public void onReConnecting() {
84 | printLog(getPrefix() + " onReConnecting");
85 | }
86 |
87 | @Override
88 | public void onReConnected() {
89 | printLog(getPrefix() + " onReConnected");
90 | }
91 |
92 | @Override
93 | public void onReConnectFailed(Exception e) {
94 | printLog(getPrefix() + " onReConnectFailed:" + e.getMessage());
95 | }
96 |
97 | @Override
98 | public void onReceiveException(Exception e) {
99 | printLog(getPrefix() + " onReceiveException:" + e.getMessage());
100 | }
101 |
102 | public void onKeepAliveTimeOut() {
103 | printLog(getPrefix() + ">>> keepAlive TimeOut...");
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
16 |
17 |
21 |
22 |
26 |
27 |
28 |
33 |
34 |
39 |
40 |
45 |
46 |
47 |
48 |
53 |
54 |
55 |
59 |
60 |
64 |
65 |
66 |
71 |
72 |
77 |
78 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/impl/socket/UdpClientSocket.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.impl.socket;
2 |
3 | import com.ethanco.halo.turbo.ads.AbstractSession;
4 | import com.ethanco.halo.turbo.ads.AbstractSocket;
5 | import com.ethanco.halo.turbo.bean.Config;
6 |
7 | import java.io.IOException;
8 | import java.util.concurrent.ExecutorService;
9 | import java.util.concurrent.Executors;
10 |
11 | /**
12 | * Udp Socket
13 | *
14 | * @author EthanCo
15 | * @since 2018/8/17
16 | */
17 |
18 | public class UdpClientSocket extends AbstractSocket {
19 | protected ExecutorService threadPool;
20 | UdpSocket socket;
21 |
22 | public UdpClientSocket(Config config) {
23 | super(config);
24 | checkConfig(config);
25 | assignThreadPool(config);
26 | initSession();
27 | }
28 |
29 | private void checkConfig(Config config) {
30 | if (config.codec != null) {
31 | throw new IllegalArgumentException("udp client not support codec");
32 | }
33 | }
34 |
35 | private void assignThreadPool(Config config) {
36 | if (config.threadPool == null) {
37 | this.threadPool = Executors.newCachedThreadPool();
38 | } else {
39 | this.threadPool = config.threadPool;
40 | }
41 | }
42 |
43 | private void initSession() {
44 | session = new DefaultSession();
45 | sessionCreated(session);
46 | }
47 |
48 | @Override
49 | public boolean isRunning() {
50 | return socket!=null;
51 | }
52 |
53 | @Override
54 | public boolean start() {
55 | //return super.start();
56 | socket = new UdpSocket(threadPool);
57 | socket.bind(config.sourcePort);
58 | socket.connect(config.targetIP, config.targetPort);
59 | sessionOpened(session);
60 | return true;
61 | }
62 |
63 | @Override
64 | public void stop() {
65 | super.stop();
66 |
67 | if (socket!=null) {
68 | socket.disconnect();
69 | socket = null;
70 | sessionClosed(session);
71 | }
72 | }
73 |
74 | protected void sent(final Object object) throws IOException {
75 | Object convertData = convert(object);
76 | if (convertData instanceof Byte[] || convertData instanceof byte[]) {
77 | sent((byte[]) convertData);
78 | } else {
79 | sent(convertData.toString().getBytes());
80 | }
81 | messageSent(session, object);
82 | }
83 |
84 | protected void sent(final byte[] buf) throws IOException {
85 | /* final DatagramPacket packet;
86 | packet = new DatagramPacket(buf, buf.length, address, config.targetPort);*/
87 | socket.send(buf, 0, buf.length);
88 | }
89 |
90 | private class DefaultSession extends AbstractSession {
91 | @Override
92 | public void write(final Object message) {
93 |
94 | threadPool.execute(new Runnable() {
95 | @Override
96 | public void run() {
97 | try {
98 | sent(message);
99 | } catch (IOException e) {
100 | e.printStackTrace();
101 | }
102 | }
103 | });
104 | }
105 |
106 | @Override
107 | public void close() {
108 | stop();
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/ethanco/sample/HomeActivity.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.databinding.DataBindingUtil;
6 | import android.os.Bundle;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.view.View;
9 |
10 | import com.ethanco.sample.databinding.ActivityHomeBinding;
11 |
12 | public class HomeActivity extends AppCompatActivity {
13 |
14 | private ActivityHomeBinding binding;
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | binding = DataBindingUtil.setContentView(this, R.layout.activity_home);
20 |
21 | binding.tvMulServer.setOnClickListener(new View.OnClickListener() {
22 | @Override
23 | public void onClick(View v) {
24 | actionStartAty(MulticastServerActivity.class);
25 | }
26 | });
27 |
28 | binding.tvMulClient.setOnClickListener(new View.OnClickListener() {
29 | @Override
30 | public void onClick(View v) {
31 | actionStartAty(MulticastClientActivity.class);
32 | }
33 | });
34 |
35 | binding.tvMinaTcpClient.setOnClickListener(new View.OnClickListener() {
36 | @Override
37 | public void onClick(View v) {
38 | actionStartAty(MinaTcpClientActivity.class);
39 | }
40 | });
41 |
42 | binding.tvMinaTcpServer.setOnClickListener(new View.OnClickListener() {
43 | @Override
44 | public void onClick(View v) {
45 | actionStartAty(MinaTcpServerActivity.class);
46 | }
47 | });
48 |
49 | binding.tvMinaTcpClientByte.setOnClickListener(new View.OnClickListener() {
50 | @Override
51 | public void onClick(View v) {
52 | actionStartAty(MinaTcpClientByteActivity.class);
53 | }
54 | });
55 |
56 | binding.tvMinaTcpServerByte.setOnClickListener(new View.OnClickListener() {
57 | @Override
58 | public void onClick(View v) {
59 | actionStartAty(MinaTcpServerByteActivity.class);
60 | }
61 | });
62 |
63 | binding.tvCommonTcpClient.setOnClickListener(new View.OnClickListener() {
64 | @Override
65 | public void onClick(View v) {
66 | actionStartAty(CommonTcpClientActivity.class);
67 | }
68 | });
69 |
70 | binding.tvMinaUdpClient.setOnClickListener(new View.OnClickListener() {
71 | @Override
72 | public void onClick(View v) {
73 | actionStartAty(MinaUdpClientActivity.class);
74 | }
75 | });
76 |
77 | binding.tvMinaUdpServer.setOnClickListener(new View.OnClickListener() {
78 | @Override
79 | public void onClick(View v) {
80 | actionStartAty(MinaUdpServerActivity.class);
81 | }
82 | });
83 |
84 | binding.tvMinaTcpHeartBeatClient.setOnClickListener(new View.OnClickListener() {
85 | @Override
86 | public void onClick(View v) {
87 | actionStartAty(MinaTcpClientHeartBeatActivity.class);
88 | }
89 | });
90 |
91 | binding.tvMinaTcpHeartBeatServer.setOnClickListener(new View.OnClickListener() {
92 | @Override
93 | public void onClick(View v) {
94 | actionStartAty(MinaTcpServerHeartBeatActivity.class);
95 | }
96 | });
97 |
98 | binding.tvUdpClient.setOnClickListener(new View.OnClickListener() {
99 | @Override
100 | public void onClick(View view) {
101 | actionStartAty(UdpClientActivity.class);
102 | }
103 | });
104 | }
105 |
106 | private void actionStartAty(Class extends Activity> cls) {
107 | Intent intent = new Intent(HomeActivity.this, cls);
108 | startActivity(intent);
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/ethanco/sample/MinaTcpServerActivity.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 | import android.widget.Toast;
8 |
9 | import com.ethanco.halo.turbo.Halo;
10 | import com.ethanco.halo.turbo.ads.IHandlerAdapter;
11 | import com.ethanco.halo.turbo.ads.ISession;
12 | import com.ethanco.halo.turbo.impl.handler.StringLogHandler;
13 | import com.ethanco.halo.turbo.type.Mode;
14 | import com.ethanco.sample.databinding.ActivityMinaTcpServerBinding;
15 |
16 | import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
17 |
18 | public class MinaTcpServerActivity extends AppCompatActivity {
19 |
20 | private static final String TAG = "Z-MinaTcpServerActivity";
21 | private ActivityMinaTcpServerBinding binding;
22 | private ScrollBottomTextWatcher watcher;
23 | private Halo halo;
24 |
25 | @Override
26 | protected void onCreate(Bundle savedInstanceState) {
27 | super.onCreate(savedInstanceState);
28 | binding = DataBindingUtil.setContentView(this, R.layout.activity_mina_tcp_server);
29 |
30 | halo = new Halo.Builder()
31 | .setMode(Mode.MINA_NIO_TCP_SERVER)
32 | .setBufferSize(2048)
33 | .setSourcePort(19701)
34 | .addHandler(new StringLogHandler(TAG))
35 | .addHandler(new DemoHandler())
36 | .build();
37 |
38 | binding.btnStartServer.setOnClickListener(new View.OnClickListener() {
39 | @Override
40 | public void onClick(View v) {
41 | new Thread() {
42 | @Override
43 | public void run() {
44 | if (halo.isRunning()) {
45 | runOnUiThread(new Runnable() {
46 | @Override
47 | public void run() {
48 | Toast.makeText(getApplication(), "已启动", Toast.LENGTH_SHORT).show();
49 | }
50 | });
51 | return;
52 | }
53 |
54 | final boolean startSuccess = halo.start();
55 | runOnUiThread(new Runnable() {
56 | @Override
57 | public void run() {
58 | String startResult = startSuccess ? "启动成功" : "启动失败";
59 | binding.tvInfo.append(startResult + "\r\n");
60 | }
61 | });
62 | }
63 | }.start();
64 | }
65 | });
66 |
67 | binding.btnStop.setOnClickListener(new View.OnClickListener() {
68 | @Override
69 | public void onClick(View v) {
70 | if (halo != null) {
71 | halo.stop();
72 | binding.tvInfo.append("停止启动" + "\r\n");
73 | }
74 | }
75 | });
76 |
77 | watcher = new ScrollBottomTextWatcher(binding.scrollView);
78 | binding.tvInfo.addTextChangedListener(watcher);
79 | }
80 |
81 | @Override
82 | protected void onDestroy() {
83 | super.onDestroy();
84 | if (halo != null) {
85 | halo.stop();
86 | }
87 |
88 | if (watcher != null) {
89 | binding.tvInfo.removeTextChangedListener(watcher);
90 | watcher = null;
91 | }
92 | }
93 |
94 | class DemoHandler extends IHandlerAdapter {
95 | @Override
96 | public void messageReceived(ISession session, Object message) {
97 | session.write("这是服务端,我已经收到数据了 --->>>666");
98 | binding.tvInfo.append("接收:" + message + "\r\n");
99 | }
100 |
101 | @Override
102 | public void messageSent(ISession session, Object message) {
103 | super.messageSent(session, message);
104 | binding.tvInfo.append("发送:" + message + "\r\n");
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/ethanco/sample/MulticastServerActivity.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 | import android.widget.Toast;
8 |
9 | import com.ethanco.halo.turbo.Halo;
10 | import com.ethanco.halo.turbo.ads.IHandlerAdapter;
11 | import com.ethanco.halo.turbo.ads.ISession;
12 | import com.ethanco.halo.turbo.impl.handler.StringLogHandler;
13 | import com.ethanco.halo.turbo.type.Mode;
14 | import com.ethanco.sample.databinding.ActivityMulticastServerBinding;
15 |
16 | import java.util.concurrent.Executors;
17 |
18 | public class MulticastServerActivity extends AppCompatActivity {
19 |
20 | public static final String TAG = "Z-Server";
21 | private ActivityMulticastServerBinding binding;
22 | private ScrollBottomTextWatcher watcher;
23 | private Halo halo;
24 |
25 | @Override
26 | protected void onCreate(Bundle savedInstanceState) {
27 | super.onCreate(savedInstanceState);
28 | binding = DataBindingUtil.setContentView(this, R.layout.activity_multicast_server);
29 |
30 | halo = new Halo.Builder()
31 | .setMode(Mode.MULTICAST)
32 | .setSourcePort(19602)
33 | .setTargetPort(19601)
34 | .setTargetIP("224.0.0.1")
35 | .setBufferSize(512)
36 | //.addHandler(new ByteLogHandler(TAG))
37 | .addHandler(new StringLogHandler(TAG))
38 | .addHandler(new DemoHandler())
39 | .setThreadPool(Executors.newCachedThreadPool())
40 | .build();
41 |
42 | binding.btnStartService.setOnClickListener(new View.OnClickListener() {
43 | @Override
44 | public void onClick(View v) {
45 | if (halo.isRunning()) {
46 | runOnUiThread(new Runnable() {
47 | @Override
48 | public void run() {
49 | Toast.makeText(MulticastServerActivity.this, "已启动", Toast.LENGTH_SHORT).show();
50 | }
51 | });
52 | return;
53 | }
54 |
55 | boolean result = halo.start();
56 | String startSuccess = result ? "启动成功" : "启动失败";
57 | binding.tvInfo.append(startSuccess + "\r\n");
58 | }
59 | });
60 |
61 | binding.btnStop.setOnClickListener(new View.OnClickListener() {
62 | @Override
63 | public void onClick(View v) {
64 | if (halo != null) {
65 | halo.stop();
66 | binding.tvInfo.append("停止启动" + "\r\n");
67 | }
68 | }
69 | });
70 |
71 | watcher = new ScrollBottomTextWatcher(binding.scrollView);
72 | binding.tvInfo.addTextChangedListener(watcher);
73 | }
74 |
75 | @Override
76 | protected void onDestroy() {
77 | super.onDestroy();
78 | if (halo != null) {
79 | halo.stop();
80 | }
81 |
82 | if (watcher != null) {
83 | binding.tvInfo.removeTextChangedListener(watcher);
84 | watcher = null;
85 | }
86 | }
87 |
88 | class DemoHandler extends IHandlerAdapter {
89 |
90 | @Override
91 | public void sessionCreated(ISession session) {
92 | binding.tvInfo.append("sessionCreated\r\n");
93 | }
94 |
95 | @Override
96 | public void sessionOpened(ISession session) {
97 | binding.tvInfo.append("sessionOpened\r\n");
98 | }
99 |
100 | @Override
101 | public void sessionClosed(ISession session) {
102 | binding.tvInfo.append("sessionClosed\r\n");
103 | }
104 |
105 | @Override
106 | public void messageReceived(ISession session, Object message) {
107 | binding.tvInfo.append("messageReceived data:" + message + "\r\n");
108 | session.write("------>>>> 回复你的");
109 | }
110 |
111 | @Override
112 | public void messageSent(ISession session, Object message) {
113 | binding.tvInfo.append("messageSent data:" + message + "\r\n");
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
15 |
16 |
21 |
22 |
26 |
27 |
28 |
29 |
33 |
34 |
35 |
36 |
40 |
41 |
42 |
43 |
47 |
48 |
49 |
50 |
54 |
55 |
56 |
57 |
61 |
62 |
63 |
64 |
68 |
69 |
70 |
71 |
75 |
76 |
77 |
78 |
82 |
83 |
84 |
85 |
89 |
90 |
91 |
92 |
96 |
97 |
98 |
99 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/ethanco/sample/MinaUdpServerActivity.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.os.Looper;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.view.View;
8 | import android.widget.Toast;
9 |
10 | import com.ethanco.halo.turbo.Halo;
11 | import com.ethanco.halo.turbo.ads.IHandlerAdapter;
12 | import com.ethanco.halo.turbo.ads.ISession;
13 | import com.ethanco.halo.turbo.impl.handler.StringLogHandler;
14 | import com.ethanco.halo.turbo.type.Mode;
15 | import com.ethanco.sample.databinding.ActivityMinaTcpServerBinding;
16 |
17 | public class MinaUdpServerActivity extends AppCompatActivity {
18 |
19 | private static final String TAG = "Z-MinaTcpServerActivity";
20 | private ActivityMinaTcpServerBinding binding;
21 | private ScrollBottomTextWatcher watcher;
22 | private Halo halo;
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | binding = DataBindingUtil.setContentView(this, R.layout.activity_mina_tcp_server);
28 |
29 | binding.btnStartServer.setOnClickListener(new View.OnClickListener() {
30 | @Override
31 | public void onClick(View v) {
32 | new Thread() {
33 | @Override
34 | public void run() {
35 | halo = new Halo.Builder()
36 | .setMode(Mode.MINA_NIO_UDP_SERVER)
37 | .setBufferSize(2048)
38 | .setSourcePort(19701)
39 | .setContext(getApplicationContext())
40 | .addHandler(new StringLogHandler(TAG))
41 | .addHandler(new DemoHandler())
42 | .build();
43 |
44 | if (halo.isRunning()) {
45 | runOnUiThread(new Runnable() {
46 | @Override
47 | public void run() {
48 | Toast.makeText(getApplication(), "已启动", Toast.LENGTH_SHORT).show();
49 | }
50 | });
51 | return;
52 | }
53 |
54 | final boolean startSuccess = halo.start();
55 | runOnUiThread(new Runnable() {
56 | @Override
57 | public void run() {
58 | String startResult = startSuccess ? "启动成功" : "启动失败";
59 | binding.tvInfo.append(startResult + "\r\n");
60 | }
61 | });
62 | }
63 | }.start();
64 | }
65 | });
66 |
67 | binding.btnStop.setOnClickListener(new View.OnClickListener() {
68 | @Override
69 | public void onClick(View v) {
70 | if (halo != null) {
71 | halo.stop();
72 | binding.tvInfo.append("停止启动" + "\r\n");
73 | }
74 | }
75 | });
76 |
77 | watcher = new ScrollBottomTextWatcher(binding.scrollView);
78 | binding.tvInfo.addTextChangedListener(watcher);
79 | }
80 |
81 | @Override
82 | protected void onDestroy() {
83 | super.onDestroy();
84 | if (halo != null) {
85 | halo.stop();
86 | }
87 |
88 | if (watcher != null) {
89 | binding.tvInfo.removeTextChangedListener(watcher);
90 | watcher = null;
91 | }
92 | }
93 |
94 | class DemoHandler extends IHandlerAdapter {
95 | @Override
96 | public void messageReceived(final ISession session, Object message) {
97 | session.write("这是服务端,我已经收到数据了 --->>>666");
98 | binding.tvInfo.append("是否是主线程" + (Looper.myLooper() == Looper.getMainLooper()) + "接收:" + message + "\r\n");
99 | }
100 |
101 | @Override
102 | public void messageSent(ISession session, Object message) {
103 | super.messageSent(session, message);
104 | binding.tvInfo.append("发送:" + message + "\r\n");
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/Halo.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo;
2 |
3 | import android.content.Context;
4 |
5 | import com.ethanco.halo.turbo.ads.AbstractHalo;
6 | import com.ethanco.halo.turbo.ads.IConvertor;
7 | import com.ethanco.halo.turbo.ads.IHandler;
8 | import com.ethanco.halo.turbo.ads.ISocket;
9 | import com.ethanco.halo.turbo.bean.Config;
10 | import com.ethanco.halo.turbo.bean.KeepAlive;
11 | import com.ethanco.halo.turbo.type.Mode;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 | import java.util.concurrent.ExecutorService;
16 |
17 | /**
18 | * Created by EthanCo on 2016/9/14.
19 | */
20 | public class Halo extends AbstractHalo {
21 | private ISocket haloImpl;
22 |
23 | public Halo() {
24 | this(new Builder());
25 | }
26 |
27 | public Halo(Builder builder) {
28 | this.haloImpl = SocketFactory.create(builder);
29 | }
30 |
31 | @Override
32 | public boolean start() {
33 | return this.haloImpl.start();
34 | }
35 |
36 | @Override
37 | public void stop() {
38 | if (haloImpl != null) {
39 | haloImpl.stop();
40 | }
41 | }
42 |
43 | @Override
44 | public List getHandlers() {
45 | return this.haloImpl.getHandlers();
46 | }
47 |
48 | @Override
49 | public void addHandler(IHandler handler) {
50 | this.haloImpl.addHandler(handler);
51 | }
52 |
53 | @Override
54 | public boolean removeHandler(IHandler handler) {
55 | return this.haloImpl.removeHandler(handler);
56 | }
57 |
58 | @Override
59 | public boolean isRunning() {
60 | return haloImpl.isRunning();
61 | }
62 |
63 | public static class Builder extends Config {
64 |
65 | public Builder() {
66 | this.mode = Mode.MINA_NIO_TCP_CLIENT;
67 | this.targetIP = "192.168.1.1";
68 | this.targetPort = 19600;
69 | //this.sourceIP = "192.168.1.1";
70 | this.sourcePort = 19700;
71 | this.bufferSize = 1024;
72 | this.handlers = new ArrayList<>();
73 | this.convertors = new ArrayList<>();
74 | //需要的自行进行初始化
75 | //this.threadPool = Executors.newCachedThreadPool();
76 | }
77 |
78 | public Builder setMode(Mode mode) {
79 | this.mode = mode;
80 | return this;
81 | }
82 |
83 | public Builder setTargetIP(String targetIP) {
84 | this.targetIP = targetIP;
85 | return this;
86 | }
87 |
88 | public Builder setTargetPort(int targetPort) {
89 | this.targetPort = targetPort;
90 | return this;
91 | }
92 |
93 | /*public Builder setSourceIP(String sourceIP) {
94 | this.sourceIP = sourceIP;
95 | return this;
96 | }*/
97 |
98 | public Builder setSourcePort(int sourcePort) {
99 | this.sourcePort = sourcePort;
100 | return this;
101 | }
102 |
103 | public Builder setBufferSize(int bufferSize) {
104 | this.bufferSize = bufferSize;
105 | return this;
106 | }
107 |
108 | public Builder setThreadPool(ExecutorService threadPool) {
109 | this.threadPool = threadPool;
110 | return this;
111 | }
112 |
113 | public Builder addHandler(IHandler handler) {
114 | if (!this.handlers.contains(handler)) {
115 | this.handlers.add(handler);
116 | }
117 | return this;
118 | }
119 |
120 | //添加转换器
121 | public Builder addConvert(IConvertor convertor) {
122 | if (!convertors.contains(convertor)) {
123 | this.convertors.add(convertor);
124 | }
125 | return this;
126 | }
127 |
128 | //这是自定义的转换器列表
129 | public Builder setConverts(List convertors) {
130 | this.convertors = convertors;
131 | return this;
132 | }
133 |
134 | //设置ProtocolCodecFactory,现仅对Mina有效
135 | public Builder setCodec(Object codec) {
136 | this.codec = codec;
137 | return this;
138 | }
139 |
140 | public Builder setContext(Context context) {
141 | this.context = context;
142 | return this;
143 | }
144 |
145 | //设置心跳
146 | public Builder setKeepAlive(KeepAlive keepAlive) {
147 | this.keepAlive = keepAlive;
148 | return this;
149 | }
150 |
151 | public Halo build() {
152 | return new Halo(this);
153 | }
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/ethanco/sample/MulticastClientActivity.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 | import android.widget.Toast;
8 |
9 | import com.ethanco.halo.turbo.Halo;
10 | import com.ethanco.halo.turbo.ads.IHandlerAdapter;
11 | import com.ethanco.halo.turbo.ads.ISession;
12 | import com.ethanco.halo.turbo.impl.handler.HexLogHandler;
13 | import com.ethanco.halo.turbo.type.Mode;
14 | import com.ethanco.json.convertor.convert.ObjectJsonByteConvertor;
15 | import com.ethanco.sample.databinding.ActivityMulticastClientBinding;
16 |
17 | import java.util.concurrent.Executors;
18 |
19 | public class MulticastClientActivity extends AppCompatActivity {
20 |
21 | private static final String TAG = "Z-Client";
22 | private ActivityMulticastClientBinding binding;
23 | private ScrollBottomTextWatcher watcher;
24 | private Halo halo;
25 | private ISession session;
26 |
27 | @Override
28 | protected void onCreate(Bundle savedInstanceState) {
29 | super.onCreate(savedInstanceState);
30 | binding = DataBindingUtil.setContentView(this, R.layout.activity_multicast_client);
31 |
32 | halo = new Halo.Builder()
33 | .setMode(Mode.MULTICAST)
34 | .setSourcePort(19601)
35 | .setTargetPort(19602)
36 | .setTargetIP("224.0.0.1")
37 | .setBufferSize(512)
38 | .addHandler(new HexLogHandler(TAG))
39 | //.addHandler(new StringLogHandler(TAG))
40 | .addHandler(new DemoHandler())
41 | .addConvert(new ObjectJsonByteConvertor())
42 | .setThreadPool(Executors.newCachedThreadPool())
43 | .build();
44 |
45 | binding.btnConnect.setOnClickListener(new View.OnClickListener() {
46 | @Override
47 | public void onClick(View v) {
48 | if (halo.isRunning()) {
49 | runOnUiThread(new Runnable() {
50 | @Override
51 | public void run() {
52 | Toast.makeText(MulticastClientActivity.this, "已启动", Toast.LENGTH_SHORT).show();
53 | }
54 | });
55 | return;
56 | }
57 |
58 | boolean result = halo.start();
59 | String startSuccess = result ? "连接成功" : "连接失败";
60 | binding.tvInfo.append(startSuccess + "\r\n");
61 | }
62 | });
63 |
64 | binding.btnSendData.setOnClickListener(new View.OnClickListener() {
65 | @Override
66 | public void onClick(View v) {
67 | //session.write("send-112233");
68 | session.write(new TestBean("cc1", "dd3"));
69 | }
70 | });
71 |
72 | binding.btnStop.setOnClickListener(new View.OnClickListener() {
73 | @Override
74 | public void onClick(View v) {
75 | if (halo != null) {
76 | halo.stop();
77 | binding.tvInfo.append("停止连接" + "\r\n");
78 | }
79 | }
80 | });
81 |
82 | watcher = new ScrollBottomTextWatcher(binding.scrollView);
83 | binding.tvInfo.addTextChangedListener(watcher);
84 | }
85 |
86 | @Override
87 | protected void onDestroy() {
88 | super.onDestroy();
89 | if (watcher != null) {
90 | binding.tvInfo.removeTextChangedListener(watcher);
91 | watcher = null;
92 | }
93 | }
94 |
95 | class DemoHandler extends IHandlerAdapter {
96 |
97 | @Override
98 | public void sessionCreated(ISession session) {
99 | binding.tvInfo.append("sessionCreated\r\n");
100 | }
101 |
102 | @Override
103 | public void sessionOpened(ISession session) {
104 | MulticastClientActivity.this.session = session;
105 | //session.write("hello");
106 | binding.tvInfo.append("sessionOpened\r\n");
107 | }
108 |
109 | @Override
110 | public void sessionClosed(ISession session) {
111 | binding.tvInfo.append("sessionClosed\r\n");
112 | }
113 |
114 | @Override
115 | public void messageReceived(ISession session, Object message) {
116 | binding.tvInfo.append("messageReceived data:" + message + "\r\n");
117 | }
118 |
119 | @Override
120 | public void messageSent(ISession session, Object message) {
121 | binding.tvInfo.append("messageSent data:" + message + "\r\n");
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/ethanco/sample/MinaTcpServerByteActivity.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 | import android.widget.Toast;
8 |
9 | import com.ethanco.halo.turbo.Halo;
10 | import com.ethanco.halo.turbo.ads.IHandlerAdapter;
11 | import com.ethanco.halo.turbo.ads.ISession;
12 | import com.ethanco.halo.turbo.impl.handler.HexLogHandler;
13 | import com.ethanco.halo.turbo.type.Mode;
14 | import com.ethanco.halo.turbo.utils.HexUtil;
15 | import com.ethanco.sample.databinding.ActivityMinaTcpServerBinding;
16 |
17 | import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
18 |
19 | public class MinaTcpServerByteActivity extends AppCompatActivity {
20 |
21 | private static final String TAG = "Z-MinaTcpServerByteActivity";
22 | private ActivityMinaTcpServerBinding binding;
23 | private ScrollBottomTextWatcher watcher;
24 | private Halo halo;
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | binding = DataBindingUtil.setContentView(this, R.layout.activity_mina_tcp_server);
30 |
31 | halo = new Halo.Builder()
32 | .setMode(Mode.MINA_NIO_TCP_SERVER)
33 | .setBufferSize(2048)
34 | .setSourcePort(19701)
35 | //.addHandler(new StringLogHandler(TAG))
36 | .addHandler(new HexLogHandler(TAG))
37 | .addHandler(new DemoHandler())
38 | .setCodec(new ObjectSerializationCodecFactory())
39 | .build();
40 |
41 | binding.btnStartServer.setOnClickListener(new View.OnClickListener() {
42 | @Override
43 | public void onClick(View v) {
44 | new Thread() {
45 | @Override
46 | public void run() {
47 | if (halo.isRunning()) {
48 | runOnUiThread(new Runnable() {
49 | @Override
50 | public void run() {
51 | Toast.makeText(getApplication(), "已启动", Toast.LENGTH_SHORT).show();
52 | }
53 | });
54 | return;
55 | }
56 |
57 | final boolean startSuccess = halo.start();
58 | runOnUiThread(new Runnable() {
59 | @Override
60 | public void run() {
61 | String startResult = startSuccess ? "启动成功" : "启动失败";
62 | binding.tvInfo.append(startResult + "\r\n");
63 | }
64 | });
65 | }
66 | }.start();
67 | }
68 | });
69 |
70 | binding.btnStop.setOnClickListener(new View.OnClickListener() {
71 | @Override
72 | public void onClick(View v) {
73 | if (halo != null) {
74 | halo.stop();
75 | binding.tvInfo.append("停止启动" + "\r\n");
76 | }
77 | }
78 | });
79 |
80 | watcher = new ScrollBottomTextWatcher(binding.scrollView);
81 | binding.tvInfo.addTextChangedListener(watcher);
82 | }
83 |
84 | @Override
85 | protected void onDestroy() {
86 | super.onDestroy();
87 | if (halo != null) {
88 | halo.stop();
89 | }
90 |
91 | if (watcher != null) {
92 | binding.tvInfo.removeTextChangedListener(watcher);
93 | watcher = null;
94 | }
95 | }
96 |
97 | class DemoHandler extends IHandlerAdapter {
98 | @Override
99 | public void messageReceived(ISession session, Object message) {
100 | //session.write("这是服务端,我已经收到数据了 --->>>666");
101 | session.write(new byte[]{0x09, 0x09, 0x09});
102 | printInfo("接收:", message);
103 | }
104 |
105 | @Override
106 | public void messageSent(ISession session, Object message) {
107 | super.messageSent(session, message);
108 | printInfo("发送:", message);
109 | }
110 | }
111 |
112 | private void printInfo(String operation, Object message) {
113 | if (message instanceof byte[] || message instanceof Byte[]) {
114 | binding.tvInfo.append(operation + HexUtil.bytesToHexString((byte[]) message) + "\r\n");
115 | } else {
116 | binding.tvInfo.append(operation + message + "\r\n");
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/ReadMe.md:
--------------------------------------------------------------------------------
1 | # Halo-Turbo #
2 | Android Socket框架
3 |
4 | ## 添加依赖 ##
5 | ### Step 1. Add the JitPack repository to your build file
6 | Add it in your root build.gradle at the end of repositories:
7 |
8 | allprojects {
9 | repositories {
10 | ...
11 | maven { url 'https://jitpack.io' }
12 | }
13 | }
14 |
15 | ### Step 2. Add the dependency
16 |
17 | dependencies {
18 | compile 'com.github.EthanCo.Halo-Turbo:halo-turbo:2.2.6'
19 | compile 'com.github.EthanCo.Halo-Turbo:halo-turbo-mina:2.2.6'
20 | compile 'com.github.EthanCo.Halo-Turbo:json-convertor:2.2.6'
21 | }
22 |
23 | > halo-turbo是核心库,带有组播功能
24 | > halo-turbo-mina:使用TCP需依赖此库
25 | > json-convertor:将需发送的对象自动转换为json字符串
26 |
27 | ## 使用 ##
28 | 注意 : 以下方法都需要在异步线程中进行调用 !!!
29 | ### TCP client
30 |
31 | Halo halo = new Halo.Builder()
32 | .setMode(Mode.MINA_NIO_TCP_CLIENT)
33 | .setTargetIP(targetIP)
34 | .setTargetPort(19701)
35 | .addHandler(new DemoHandler())
36 | .build();
37 | boolean result = halo.start();
38 |
39 | ### TCP Server
40 |
41 | Halo halo = new Halo.Builder()
42 | .setMode(Mode.MINA_NIO_TCP_SERVER)
43 | .setSourcePort(19701)
44 | .addHandler(new DemoHandler())
45 | .build();
46 | boolean result = halo.start();
47 |
48 | ### 组播
49 |
50 | Halo halo = new Halo.Builder()
51 | .setMode(Mode.MULTICAST)
52 | .setSourcePort(19601)
53 | .setTargetPort(19602)
54 | .setTargetIP("224.0.0.1")
55 | .addHandler(new DemoHandler())
56 | .build();
57 | boolean result = halo.start();
58 |
59 | ### UDP Client
60 |
61 | halo = new Halo.Builder()
62 | .setMode(Mode.MINA_NIO_UDP_CLIENT)
63 | .setTargetIP(targetIP)
64 | .setTargetPort(19701)
65 | .setContext(context)
66 | .build();
67 | boolean result = halo.start();
68 |
69 | ### UDP Server
70 |
71 | halo = new Halo.Builder()
72 | .setMode(Mode.MINA_NIO_UDP_SERVER)
73 | .setSourcePort(19701)
74 | .setContext(context)
75 | .build();
76 | boolean result = halo.start();
77 |
78 | ### 添加回调处理
79 |
80 | new Halo.Builder().addHandler(new DemoHandler())
81 |
82 | **说明:**
83 | 1. 可通过addHandler()设置回调
84 | 2. 可使用session来发送数据和管理连接
85 |
86 | #####
87 | public interface IHandler {
88 | //会话(session)创建之后,回调该方法
89 | void sessionCreated(ISession session);
90 |
91 | //会话(session)打开之后,回调该方法
92 | void sessionOpened(ISession session);
93 |
94 | //会话(session)关闭后,回调该方法
95 | void sessionClosed(ISession session);
96 |
97 | //接收到消息时回调这个方法
98 | void messageReceived(ISession session, Object message);
99 |
100 | //发送数据时回调这个方法
101 | void messageSent(ISession session, Object message);
102 | }
103 |
104 | ## 添加心跳
105 | 添加心跳后,如果是Client端,如进行断线,会自动进行断线重连。
106 | 如果是Server端,收到心跳后,会进行反馈。
107 |
108 | builder.setKeepAlive(new KeepAlive(15, 60, new IKeepAliveListener() {
109 | @Override
110 | public void onKeepAliveRequestTimedOut(KeepAlive keepAlive, ISession iSession) {
111 | //心跳超时
112 | }
113 |
114 | @Override
115 | public boolean isKeepAliveMessage(ISession ioSession, Object message) {
116 | //是否是心跳
117 | }
118 |
119 | @Override
120 | public Object getKeepAliveMessage(ISession ioSession, Object o) {
121 | //返回心跳数据
122 | }
123 | }))
124 |
125 | > KeepAlive
126 | > interval:每次心跳的间隔时间
127 | > timeout:心跳未收到的超时时间
128 | > reConnTime:重连间隔时间,默认60秒一次
129 |
130 | ## 添加日志打印
131 |
132 | new Halo.Builder().addHandler(new StringLogHandler(TAG))
133 |
134 | Halo默认实现了如下几个日志打印类,亦可自定义日志打印
135 |
136 | StringLogHandler:默认日志打印,打印成字符串
137 | HexLogHandler:Byte日志打印,如果是byte数组,将打印成十六进制
138 |
139 | ## 添加转换器
140 | 通过连接转换器,可在发送数据时,自动转换为相关类别
141 |
142 | new Halo.Builder().addConvert(new ObjectJsonConvertor())
143 |
144 | Halo默认提供了如下转换器,亦可自定义转换器
145 |
146 | ObjectJsonConvertor:发送Object对象时,自动将其转换为Json字符串
147 |
148 | session.write(object); //发送object时自动转换为json字符串再发送
149 |
150 | ObjectJsonByteConvertor:如果是Object对象,则先转换为json字符串后,再转换为byte[]
151 |
152 | 使用如上转换器,需格外添加依赖
153 |
154 | dependencies {
155 | //...
156 | compile 'com.github.EthanCo.Halo-Turbo:json-convertor:X.X.X'
157 | }
158 |
159 | ## setBufferSize
160 | 设置Buffer大小
161 |
162 | ## setThreadPool
163 | 设置自定义线程池
164 |
165 | ## setCodec
166 | 现仅用作Mina设置ProtocolCodecFactory
167 |
168 | 默认情况下,Halo-Turbo是用于接收、发送String类型数据,每条数据的结尾都会加上`\n`用于区分多条数据。(如果是普通的Socket 发送数据给Halo-Turbo,普通Socket发送的数据在发送时需要手动在数据末尾添加`\n`)
169 | 如果需要自定义分隔标识符,可以进行如下设置。
170 |
171 | builder.setCodec(new TextLineCodecFactory(
172 | Charset.forName(编码格式 - 比如UTF-8), encode的分隔标识符, decode的分隔标识符)
173 |
174 | 如果不是发送String类型的数据,需要通过builder.setCodec设置不同的解码类
175 | TextLineCodecFactory:基于文本的,根据回车换行来断点传输数据
176 | ProtocolCodecFactory:自定义协议的编解码数据传输
177 | ObjectSerializationCodecFactory:对象序列化传输
178 | DemuxingProtocolCodecFactory:复用传输
179 |
180 | ## 其他
181 |
182 | 具体详见Sample
183 |
184 |
185 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/ethanco/sample/MinaTcpServerHeartBeatActivity.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.util.Log;
7 | import android.view.View;
8 | import android.widget.Toast;
9 |
10 | import com.ethanco.halo.turbo.Halo;
11 | import com.ethanco.halo.turbo.ads.IHandlerAdapter;
12 | import com.ethanco.halo.turbo.ads.IKeepAliveListener;
13 | import com.ethanco.halo.turbo.ads.ISession;
14 | import com.ethanco.halo.turbo.bean.KeepAlive;
15 | import com.ethanco.halo.turbo.impl.handler.StringLogHandler;
16 | import com.ethanco.halo.turbo.type.Mode;
17 | import com.ethanco.sample.databinding.ActivityMinaTcpServerBinding;
18 |
19 | public class MinaTcpServerHeartBeatActivity extends AppCompatActivity {
20 |
21 | private static final String TAG = "Z-MinaTcpServerActivity";
22 | private ActivityMinaTcpServerBinding binding;
23 | private ScrollBottomTextWatcher watcher;
24 | private Halo halo;
25 | public static final String HEART_BEAT = "heartbeat";
26 |
27 | @Override
28 | protected void onCreate(Bundle savedInstanceState) {
29 | super.onCreate(savedInstanceState);
30 | binding = DataBindingUtil.setContentView(this, R.layout.activity_mina_tcp_server);
31 |
32 | halo = new Halo.Builder()
33 | .setMode(Mode.MINA_NIO_TCP_SERVER)
34 | .setBufferSize(2048)
35 | .setSourcePort(19701)
36 | .addHandler(new StringLogHandler(TAG))
37 | .addHandler(new DemoHandler())
38 | .setKeepAlive(new KeepAlive(15, 60, keepAliveListener))
39 | .build();
40 |
41 | binding.btnStartServer.setOnClickListener(new View.OnClickListener() {
42 | @Override
43 | public void onClick(View v) {
44 | new Thread() {
45 | @Override
46 | public void run() {
47 | if (halo.isRunning()) {
48 | runOnUiThread(new Runnable() {
49 | @Override
50 | public void run() {
51 | Toast.makeText(getApplication(), "已启动", Toast.LENGTH_SHORT).show();
52 | }
53 | });
54 | return;
55 | }
56 |
57 | final boolean startSuccess = halo.start();
58 | runOnUiThread(new Runnable() {
59 | @Override
60 | public void run() {
61 | String startResult = startSuccess ? "启动成功" : "启动失败";
62 | binding.tvInfo.append(startResult + "\r\n");
63 | }
64 | });
65 | }
66 | }.start();
67 | }
68 | });
69 |
70 | binding.btnStop.setOnClickListener(new View.OnClickListener() {
71 | @Override
72 | public void onClick(View v) {
73 | if (halo != null) {
74 | halo.stop();
75 | binding.tvInfo.append("停止启动" + "\r\n");
76 | }
77 | }
78 | });
79 |
80 | watcher = new ScrollBottomTextWatcher(binding.scrollView);
81 | binding.tvInfo.addTextChangedListener(watcher);
82 | }
83 |
84 | @Override
85 | protected void onDestroy() {
86 | super.onDestroy();
87 | if (halo != null) {
88 | halo.stop();
89 | }
90 |
91 | if (watcher != null) {
92 | binding.tvInfo.removeTextChangedListener(watcher);
93 | watcher = null;
94 | }
95 | }
96 |
97 | class DemoHandler extends IHandlerAdapter {
98 | @Override
99 | public void messageReceived(ISession session, Object message) {
100 | session.write("这是服务端,我已经收到数据了 --->>>666");
101 | binding.tvInfo.append("接收:" + message + "\r\n");
102 | }
103 |
104 | @Override
105 | public void messageSent(ISession session, Object message) {
106 | super.messageSent(session, message);
107 | binding.tvInfo.append("发送:" + message + "\r\n");
108 | }
109 | }
110 |
111 | private IKeepAliveListener keepAliveListener = new IKeepAliveListener() {
112 | @Override
113 | public void onKeepAliveRequestTimedOut(KeepAlive keepAlive, ISession iSession) {
114 | Log.i(TAG, "onKeepAliveRequestTimedOut...");
115 | }
116 |
117 | @Override
118 | public boolean isKeepAliveMessage(ISession ioSession, Object message) {
119 | if (message == null) return false;
120 | if (message instanceof String) {
121 | return message.equals(HEART_BEAT);
122 | }
123 | return false;
124 | }
125 |
126 | @Override
127 | public Object getKeepAliveMessage(ISession ioSession, Object o) {
128 | return HEART_BEAT;
129 | }
130 | };
131 | }
132 |
--------------------------------------------------------------------------------
/halo-turbo-mina/src/main/java/com/ethanco/halo/turbo/mina/MinaTcpServerSocket.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.mina;
2 |
3 | import com.ethanco.halo.turbo.ads.AbstractSocket;
4 | import com.ethanco.halo.turbo.bean.Config;
5 |
6 | import org.apache.mina.core.service.IoHandlerAdapter;
7 | import org.apache.mina.core.session.IdleStatus;
8 | import org.apache.mina.core.session.IoSession;
9 | import org.apache.mina.filter.codec.ProtocolCodecFactory;
10 | import org.apache.mina.filter.codec.ProtocolCodecFilter;
11 | import org.apache.mina.filter.keepalive.KeepAliveFilter;
12 | import org.apache.mina.filter.logging.LoggingFilter;
13 | import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
14 |
15 | import java.io.IOException;
16 | import java.net.InetSocketAddress;
17 |
18 | import static com.ethanco.halo.turbo.mina.MinaUtil.CODEC;
19 | import static com.ethanco.halo.turbo.mina.MinaUtil.HEARTBEAT;
20 | import static com.ethanco.halo.turbo.mina.MinaUtil.LOGGER;
21 | import static com.ethanco.halo.turbo.mina.MinaUtil.convertToISession;
22 |
23 | /**
24 | * Mina Nio Tcp Server
25 | *
26 | * @author EthanCo
27 | * @since 2017/1/17
28 | */
29 |
30 | public class MinaTcpServerSocket extends AbstractSocket {
31 |
32 | private NioSocketAcceptor acceptor;
33 | private InetSocketAddress address;
34 |
35 | public MinaTcpServerSocket(Config config) {
36 | super(config);
37 | }
38 |
39 | private void init(Config config) {
40 | address = new InetSocketAddress(config.sourcePort);
41 | acceptor = new NioSocketAcceptor();
42 | if (acceptor.getFilterChain().get(LOGGER) == null) {
43 | acceptor.getFilterChain().addLast(LOGGER, new LoggingFilter());
44 | }
45 | if (acceptor.getFilterChain().get(CODEC) == null) {
46 | ProtocolCodecFactory codecFactory = config.codec == null ?
47 | MinaUtil.getTextLineCodecFactory() : (ProtocolCodecFactory) config.codec;
48 | acceptor.getFilterChain().addLast(CODEC, new ProtocolCodecFilter(codecFactory));
49 | }
50 | acceptor.setHandler(new MinaServerHandler());
51 | acceptor.getSessionConfig().setReadBufferSize(config.bufferSize);
52 | acceptor.getSessionConfig().setIdleTime(IdleStatus.WRITER_IDLE, 10);
53 | acceptor.setReuseAddress(true); //避免重启时提示地址被占用
54 | //设置主服务监听端口的监听队列的最大值为50,如果当前已经有50个连接,新的连接将被服务器拒绝
55 | acceptor.setBacklog(50);
56 |
57 | KeepAliveFilter keepAliveFilter = MinaUtil.initServerKeepAlive(config, this);
58 | if (keepAliveFilter != null) {
59 | acceptor.getFilterChain().addLast(HEARTBEAT, keepAliveFilter);
60 | }
61 | }
62 |
63 | @Override
64 | public boolean start() {
65 | super.start();
66 | if (isRunning()) {
67 | return false;
68 | }
69 |
70 | init(config);
71 | try {
72 | acceptor.bind(address);
73 | } catch (IOException e) {
74 | onStartFailed(e);
75 | return false;
76 | }
77 |
78 | onStartSuccess();
79 | return true;
80 | }
81 |
82 | @Override
83 | public void stop() {
84 | super.stop();
85 | if (acceptor == null) {
86 | return;
87 | }
88 | if (acceptor.isDisposed() || acceptor.isDisposing()) {
89 | return;
90 | }
91 |
92 | acceptor.unbind(address);
93 | acceptor.dispose();
94 | acceptor = null;
95 | address = null;
96 |
97 | onStopped();
98 | }
99 |
100 | @Override
101 | public boolean isRunning() {
102 | if (acceptor == null) {
103 | return false;
104 | }
105 |
106 | return acceptor.isActive();
107 | }
108 |
109 | private class MinaServerHandler extends IoHandlerAdapter {
110 | @Override
111 | public void sessionCreated(IoSession session) throws Exception {
112 | super.sessionCreated(session);
113 | MinaTcpServerSocket.this.sessionCreated(convertToISession(session, MinaTcpServerSocket.this));
114 | }
115 |
116 | @Override
117 | public void sessionOpened(IoSession session) throws Exception {
118 | super.sessionOpened(session);
119 | MinaTcpServerSocket.this.sessionOpened(convertToISession(session, MinaTcpServerSocket.this));
120 | }
121 |
122 | @Override
123 | public void messageReceived(IoSession session, Object message) throws Exception {
124 | super.messageReceived(session, message);
125 | MinaTcpServerSocket.this.messageReceived(convertToISession(session, MinaTcpServerSocket.this), receive(message));
126 | }
127 |
128 | @Override
129 | public void messageSent(IoSession session, Object message) throws Exception {
130 | super.messageSent(session, message);
131 | //MinaServerSocket.this.messageSent(convertToISession(session, MinaServerSocket.this), message);
132 | }
133 |
134 | @Override
135 | public void sessionClosed(IoSession session) throws Exception {
136 | super.sessionClosed(session);
137 | MinaTcpServerSocket.this.sessionClosed(convertToISession(session, MinaTcpServerSocket.this));
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/ethanco/sample/MinaTcpClientActivity.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.text.TextUtils;
7 | import android.view.View;
8 | import android.widget.Toast;
9 |
10 | import com.ethanco.halo.turbo.Halo;
11 | import com.ethanco.halo.turbo.ads.IHandlerAdapter;
12 | import com.ethanco.halo.turbo.ads.ISession;
13 | import com.ethanco.halo.turbo.impl.handler.StringLogHandler;
14 | import com.ethanco.halo.turbo.type.Mode;
15 | import com.ethanco.json.convertor.convert.ObjectJsonConvertor;
16 | import com.ethanco.sample.databinding.ActivityMinaTcpClientBinding;
17 |
18 | public class MinaTcpClientActivity extends AppCompatActivity {
19 |
20 | private static final String TAG = "Z-MinaTcpClientActivity";
21 | private ActivityMinaTcpClientBinding binding;
22 | private ScrollBottomTextWatcher watcher;
23 | private ISession session;
24 | private Halo halo;
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | binding = DataBindingUtil.setContentView(this, R.layout.activity_mina_tcp_client);
30 |
31 | binding.btnConnect.setOnClickListener(new View.OnClickListener() {
32 | @Override
33 | public void onClick(View v) {
34 | final String targetIP = binding.etTargetIp.getText().toString();
35 | if (TextUtils.isEmpty(targetIP)) {
36 | Toast.makeText(MinaTcpClientActivity.this, "目标IP不能为空", Toast.LENGTH_SHORT).show();
37 | }
38 |
39 | new Thread() {
40 | @Override
41 | public void run() {
42 | if (halo == null) {
43 | halo = new Halo.Builder()
44 | .setMode(Mode.MINA_NIO_TCP_CLIENT)
45 | .setBufferSize(2048)
46 | .setTargetIP(targetIP)
47 | .setTargetPort(19701)
48 | .addHandler(new StringLogHandler(TAG))
49 | .addHandler(new DemoHandler())
50 | .addConvert(new ObjectJsonConvertor()) //增加转换器 -> write的时候自动转换为Json字符串
51 | .build();
52 | }
53 |
54 | if (halo.isRunning()) {
55 | runOnUiThread(new Runnable() {
56 | @Override
57 | public void run() {
58 | Toast.makeText(getApplication(), "已启动", Toast.LENGTH_SHORT).show();
59 | }
60 | });
61 | return;
62 | }
63 |
64 | final boolean startSuccess = halo.start();
65 | runOnUiThread(new Runnable() {
66 | @Override
67 | public void run() {
68 | String connectResult = startSuccess ? "连接成功" : "连接失败";
69 | binding.tvInfo.append(connectResult + "\r\n");
70 | }
71 | });
72 | }
73 | }.start();
74 | }
75 | });
76 |
77 | binding.btnSendData.setOnClickListener(new View.OnClickListener() {
78 | @Override
79 | public void onClick(View v) {
80 | if (session == null) {
81 | Toast.makeText(MinaTcpClientActivity.this, "未建立连接", Toast.LENGTH_SHORT).show();
82 | } else {
83 | //session.write("hello,这是从Client发送的数据");
84 | session.write(new TestBean("aaa", "bbb"));
85 | }
86 | }
87 | });
88 |
89 | binding.btnStop.setOnClickListener(new View.OnClickListener() {
90 | @Override
91 | public void onClick(View v) {
92 | if (halo != null) {
93 | halo.stop();
94 | binding.tvInfo.append("停止连接" + "\r\n");
95 | }
96 | }
97 | });
98 |
99 | watcher = new ScrollBottomTextWatcher(binding.scrollView);
100 | binding.tvInfo.addTextChangedListener(watcher);
101 | }
102 |
103 | @Override
104 | protected void onDestroy() {
105 | super.onDestroy();
106 | if (watcher != null) {
107 | binding.tvInfo.removeTextChangedListener(watcher);
108 | watcher = null;
109 | }
110 | }
111 |
112 | class DemoHandler extends IHandlerAdapter {
113 |
114 | @Override
115 | public void sessionOpened(final ISession session) {
116 | MinaTcpClientActivity.this.session = session;
117 | //session.write("hello aaabbb");
118 | }
119 |
120 | @Override
121 | public void messageReceived(ISession session, Object message) {
122 | String receive = String.valueOf(message);
123 | binding.tvInfo.append("接收:" + receive + "\r\n");
124 | }
125 |
126 | @Override
127 | public void messageSent(ISession session, Object message) {
128 | super.messageSent(session, message);
129 | binding.tvInfo.append("发送:" + message + "\r\n");
130 | }
131 |
132 | @Override
133 | public void sessionClosed(ISession session) {
134 | super.sessionClosed(session);
135 | MinaTcpClientActivity.this.session = null;
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/ethanco/sample/UdpClientActivity.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.text.TextUtils;
7 | import android.view.View;
8 | import android.widget.Toast;
9 |
10 | import com.ethanco.halo.turbo.Halo;
11 | import com.ethanco.halo.turbo.ads.IHandlerAdapter;
12 | import com.ethanco.halo.turbo.ads.ISession;
13 | import com.ethanco.halo.turbo.impl.handler.StringLogHandler;
14 | import com.ethanco.halo.turbo.type.Mode;
15 | import com.ethanco.json.convertor.convert.ObjectJsonConvertor;
16 | import com.ethanco.sample.databinding.ActivityMinaTcpClientBinding;
17 |
18 | public class UdpClientActivity extends AppCompatActivity {
19 |
20 | private static final String TAG = "Z-MinaTcpClientActivity";
21 | private ActivityMinaTcpClientBinding binding;
22 | private ScrollBottomTextWatcher watcher;
23 | private ISession session;
24 | private Halo halo;
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | binding = DataBindingUtil.setContentView(this, R.layout.activity_mina_tcp_client);
30 |
31 | binding.btnConnect.setOnClickListener(new View.OnClickListener() {
32 | @Override
33 | public void onClick(View v) {
34 | final String targetIP = binding.etTargetIp.getText().toString();
35 | if (TextUtils.isEmpty(targetIP)) {
36 | Toast.makeText(UdpClientActivity.this, "目标IP不能为空", Toast.LENGTH_SHORT).show();
37 | }
38 |
39 | new Thread() {
40 | @Override
41 | public void run() {
42 | if (halo == null) {
43 | halo = new Halo.Builder()
44 | .setMode(Mode.UDP_CLIENT)
45 | .setBufferSize(2048)
46 | .setTargetIP(targetIP)
47 | .setTargetPort(19701)
48 | //.setSourcePort(57880) 设置本地端口
49 | .setContext(getApplicationContext())
50 | .addHandler(new StringLogHandler(TAG))
51 | .addHandler(new DemoHandler())
52 | .addConvert(new ObjectJsonConvertor()) //增加转换器 -> write的时候自动转换为Json字符串
53 | .build();
54 | }
55 |
56 | if (halo.isRunning()) {
57 | runOnUiThread(new Runnable() {
58 | @Override
59 | public void run() {
60 | Toast.makeText(getApplication(), "已启动", Toast.LENGTH_SHORT).show();
61 | }
62 | });
63 | return;
64 | }
65 |
66 | final boolean startSuccess = halo.start();
67 | runOnUiThread(new Runnable() {
68 | @Override
69 | public void run() {
70 | String connectResult = startSuccess ? "连接成功" : "连接失败";
71 | binding.tvInfo.append(connectResult + "\r\n");
72 | }
73 | });
74 | }
75 | }.start();
76 | }
77 | });
78 |
79 | binding.btnSendData.setOnClickListener(new View.OnClickListener() {
80 | @Override
81 | public void onClick(View v) {
82 | if (session == null) {
83 | Toast.makeText(UdpClientActivity.this, "未建立连接", Toast.LENGTH_SHORT).show();
84 | } else {
85 | //session.write("hello,这是从Client发送的数据");
86 | session.write(new TestBean("aaa", "bbb"));
87 | }
88 | }
89 | });
90 |
91 | binding.btnStop.setOnClickListener(new View.OnClickListener() {
92 | @Override
93 | public void onClick(View v) {
94 | if (halo != null) {
95 | halo.stop();
96 | binding.tvInfo.append("停止连接" + "\r\n");
97 | }
98 | }
99 | });
100 |
101 | watcher = new ScrollBottomTextWatcher(binding.scrollView);
102 | binding.tvInfo.addTextChangedListener(watcher);
103 | }
104 |
105 | @Override
106 | protected void onDestroy() {
107 | super.onDestroy();
108 | if (watcher != null) {
109 | binding.tvInfo.removeTextChangedListener(watcher);
110 | watcher = null;
111 | }
112 | }
113 |
114 | class DemoHandler extends IHandlerAdapter {
115 |
116 | @Override
117 | public void sessionOpened(final ISession session) {
118 | UdpClientActivity.this.session = session;
119 | //session.write("hello aaabbb");
120 | }
121 |
122 | @Override
123 | public void messageReceived(ISession session, Object message) {
124 | String receive = String.valueOf(message);
125 | binding.tvInfo.append("接收:" + receive + "\r\n");
126 | }
127 |
128 | @Override
129 | public void messageSent(ISession session, Object message) {
130 | super.messageSent(session, message);
131 | binding.tvInfo.append("发送:" + message + "\r\n");
132 | }
133 |
134 | @Override
135 | public void sessionClosed(ISession session) {
136 | super.sessionClosed(session);
137 | UdpClientActivity.this.session = null;
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/ethanco/sample/MinaUdpClientActivity.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.text.TextUtils;
7 | import android.view.View;
8 | import android.widget.Toast;
9 |
10 | import com.ethanco.halo.turbo.Halo;
11 | import com.ethanco.halo.turbo.ads.IHandlerAdapter;
12 | import com.ethanco.halo.turbo.ads.ISession;
13 | import com.ethanco.halo.turbo.impl.handler.StringLogHandler;
14 | import com.ethanco.halo.turbo.type.Mode;
15 | import com.ethanco.json.convertor.convert.ObjectJsonConvertor;
16 | import com.ethanco.sample.databinding.ActivityMinaTcpClientBinding;
17 |
18 | public class MinaUdpClientActivity extends AppCompatActivity {
19 |
20 | private static final String TAG = "Z-MinaTcpClientActivity";
21 | private ActivityMinaTcpClientBinding binding;
22 | private ScrollBottomTextWatcher watcher;
23 | private ISession session;
24 | private Halo halo;
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | binding = DataBindingUtil.setContentView(this, R.layout.activity_mina_tcp_client);
30 |
31 | binding.btnConnect.setOnClickListener(new View.OnClickListener() {
32 | @Override
33 | public void onClick(View v) {
34 | final String targetIP = binding.etTargetIp.getText().toString();
35 | if (TextUtils.isEmpty(targetIP)) {
36 | Toast.makeText(MinaUdpClientActivity.this, "目标IP不能为空", Toast.LENGTH_SHORT).show();
37 | }
38 |
39 | new Thread() {
40 | @Override
41 | public void run() {
42 | if (halo == null) {
43 | halo = new Halo.Builder()
44 | .setMode(Mode.MINA_NIO_UDP_CLIENT)
45 | .setBufferSize(2048)
46 | .setTargetIP(targetIP)
47 | .setTargetPort(19701)
48 | //.setSourcePort(57880) 设置本地端口
49 | .setContext(getApplicationContext())
50 | .addHandler(new StringLogHandler(TAG))
51 | .addHandler(new DemoHandler())
52 | .addConvert(new ObjectJsonConvertor()) //增加转换器 -> write的时候自动转换为Json字符串
53 | .build();
54 | }
55 |
56 | if (halo.isRunning()) {
57 | runOnUiThread(new Runnable() {
58 | @Override
59 | public void run() {
60 | Toast.makeText(getApplication(), "已启动", Toast.LENGTH_SHORT).show();
61 | }
62 | });
63 | return;
64 | }
65 |
66 | final boolean startSuccess = halo.start();
67 | runOnUiThread(new Runnable() {
68 | @Override
69 | public void run() {
70 | String connectResult = startSuccess ? "连接成功" : "连接失败";
71 | binding.tvInfo.append(connectResult + "\r\n");
72 | }
73 | });
74 | }
75 | }.start();
76 | }
77 | });
78 |
79 | binding.btnSendData.setOnClickListener(new View.OnClickListener() {
80 | @Override
81 | public void onClick(View v) {
82 | if (session == null) {
83 | Toast.makeText(MinaUdpClientActivity.this, "未建立连接", Toast.LENGTH_SHORT).show();
84 | } else {
85 | //session.write("hello,这是从Client发送的数据");
86 | session.write(new TestBean("aaa", "bbb"));
87 | }
88 | }
89 | });
90 |
91 | binding.btnStop.setOnClickListener(new View.OnClickListener() {
92 | @Override
93 | public void onClick(View v) {
94 | if (halo != null) {
95 | halo.stop();
96 | binding.tvInfo.append("停止连接" + "\r\n");
97 | }
98 | }
99 | });
100 |
101 | watcher = new ScrollBottomTextWatcher(binding.scrollView);
102 | binding.tvInfo.addTextChangedListener(watcher);
103 | }
104 |
105 | @Override
106 | protected void onDestroy() {
107 | super.onDestroy();
108 | if (watcher != null) {
109 | binding.tvInfo.removeTextChangedListener(watcher);
110 | watcher = null;
111 | }
112 | }
113 |
114 | class DemoHandler extends IHandlerAdapter {
115 |
116 | @Override
117 | public void sessionOpened(final ISession session) {
118 | MinaUdpClientActivity.this.session = session;
119 | //session.write("hello aaabbb");
120 | }
121 |
122 | @Override
123 | public void messageReceived(ISession session, Object message) {
124 | String receive = String.valueOf(message);
125 | binding.tvInfo.append("接收:" + receive + "\r\n");
126 | }
127 |
128 | @Override
129 | public void messageSent(ISession session, Object message) {
130 | super.messageSent(session, message);
131 | binding.tvInfo.append("发送:" + message + "\r\n");
132 | }
133 |
134 | @Override
135 | public void sessionClosed(ISession session) {
136 | super.sessionClosed(session);
137 | MinaUdpClientActivity.this.session = null;
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/impl/socket/MulticastSocket.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.impl.socket;
2 |
3 | import com.ethanco.halo.turbo.ads.AbstractSession;
4 | import com.ethanco.halo.turbo.ads.AbstractSocket;
5 | import com.ethanco.halo.turbo.bean.Config;
6 | import com.ethanco.halo.turbo.impl.convert.ObjectByteConvertor;
7 | import com.ethanco.halo.turbo.impl.convert.StringByteConvertor;
8 |
9 | import java.io.IOException;
10 | import java.net.DatagramPacket;
11 | import java.net.InetAddress;
12 | import java.util.concurrent.ExecutorService;
13 | import java.util.concurrent.Executors;
14 |
15 | /**
16 | * @author EthanCo
17 | * @since 2017/1/17
18 | */
19 |
20 | public class MulticastSocket extends AbstractSocket {
21 |
22 | protected InetAddress address = null;
23 | protected java.net.MulticastSocket socket = null;
24 | protected ExecutorService threadPool;
25 |
26 | public MulticastSocket(Config config) {
27 | super(config);
28 | checkConfig(config);
29 | initConvertors();
30 | assignThreadPool(config);
31 | initSession();
32 | }
33 |
34 | private void checkConfig(Config config) {
35 | if (config.codec != null) {
36 | throw new IllegalArgumentException("multicast not support codec");
37 | }
38 | }
39 |
40 | private void initConvertors() {
41 | //add default convertor
42 | convertManager.add(new StringByteConvertor());
43 | convertManager.add(new ObjectByteConvertor());
44 | }
45 |
46 | private void initSession() {
47 | session = new DefaultSession();
48 | sessionCreated(session);
49 | }
50 |
51 | private void assignThreadPool(Config config) {
52 | if (config.threadPool == null) {
53 | this.threadPool = Executors.newCachedThreadPool();
54 | } else {
55 | this.threadPool = config.threadPool;
56 | }
57 | }
58 |
59 | @Override
60 | public boolean start() {
61 | super.start();
62 | if (isRunning()) {
63 | return false;
64 | }
65 |
66 | try {
67 | socket = new java.net.MulticastSocket(config.sourcePort);
68 | address = InetAddress.getByName(config.targetIP);
69 | socket.joinGroup(address);
70 | sessionOpened(session);
71 | } catch (IOException e) {
72 | onStartFailed(e);
73 | return false;
74 | }
75 |
76 | threadPool.execute(new Runnable() {
77 | @Override
78 | public void run() {
79 | while (isRunning()) {
80 | try {
81 | receive();
82 | } catch (IOException e) {
83 | onReceiveException(e);
84 | }
85 | }
86 | }
87 | });
88 |
89 | onStartSuccess();
90 | return true;
91 | }
92 |
93 | @Override
94 | public void stop() {
95 | super.stop();
96 | if (socket == null) {
97 | return;
98 | }
99 | if (socket.isClosed()) {
100 | socket = null;
101 | return;
102 | }
103 |
104 | try {
105 | socket.leaveGroup(address);
106 | } catch (IOException e) {
107 | e.printStackTrace();
108 | } finally {
109 | socket.close();
110 | socket = null;
111 | sessionClosed(session);
112 | onStopped();
113 | }
114 | }
115 |
116 | @Override
117 | public boolean isRunning() {
118 | return socket != null;
119 | }
120 |
121 | protected void sent(final Object object) throws IOException {
122 | Object convertData = convert(object);
123 | if (convertData instanceof Byte[] || convertData instanceof byte[]) {
124 | sent((byte[]) convertData);
125 | } else {
126 | sent(convertData.toString().getBytes());
127 | }
128 | messageSent(session, object);
129 | }
130 |
131 | protected void sent(final byte[] buf) throws IOException {
132 | final DatagramPacket packet;
133 | packet = new DatagramPacket(buf, buf.length, address, config.targetPort);
134 | socket.send(packet);
135 | }
136 |
137 | protected void receive() throws IOException {
138 | final DatagramPacket packet;
139 | byte[] rev = new byte[config.bufferSize];
140 | packet = new DatagramPacket(rev, rev.length);
141 | if (socket != null) {
142 | socket.receive(packet);
143 | Object receive = receive(packet.getData());
144 | messageReceived(session, receive);
145 | }
146 | }
147 |
148 | private class DefaultSession extends AbstractSession {
149 | @Override
150 | public void write(final Object message) {
151 |
152 | threadPool.execute(new Runnable() {
153 | @Override
154 | public void run() {
155 | try {
156 | sent(message);
157 | } catch (IOException e) {
158 | e.printStackTrace();
159 | }
160 | }
161 | });
162 | }
163 |
164 | @Override
165 | public void close() {
166 | stop();
167 | }
168 |
169 | /*private byte[] convertToBuffer(Object message) {
170 | byte[] buf = null;
171 | if (message instanceof byte[]) {
172 | buf = (byte[]) (message);
173 | } else if (message instanceof String) {
174 | String s = String.valueOf(message);
175 | buf = s.getBytes();
176 | } else {
177 |
178 | }
179 |
180 | if (buf == null) {
181 | return null;
182 | }
183 | return buf;
184 | }*/
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/halo-turbo-mina/src/main/java/com/ethanco/halo/turbo/mina/MinaUdpServerSocket.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.mina;
2 |
3 | import android.content.Context;
4 | import android.net.wifi.WifiManager;
5 |
6 | import com.ethanco.halo.turbo.ads.AbstractSocket;
7 | import com.ethanco.halo.turbo.bean.Config;
8 |
9 | import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
10 | import org.apache.mina.core.service.IoHandlerAdapter;
11 | import org.apache.mina.core.session.IdleStatus;
12 | import org.apache.mina.core.session.IoSession;
13 | import org.apache.mina.filter.codec.ProtocolCodecFactory;
14 | import org.apache.mina.filter.codec.ProtocolCodecFilter;
15 | import org.apache.mina.filter.keepalive.KeepAliveFilter;
16 | import org.apache.mina.filter.logging.LoggingFilter;
17 | import org.apache.mina.transport.socket.DatagramSessionConfig;
18 | import org.apache.mina.transport.socket.nio.NioDatagramAcceptor;
19 |
20 | import java.io.IOException;
21 | import java.net.InetSocketAddress;
22 |
23 | import static com.ethanco.halo.turbo.mina.MinaUtil.CODEC;
24 | import static com.ethanco.halo.turbo.mina.MinaUtil.HEARTBEAT;
25 | import static com.ethanco.halo.turbo.mina.MinaUtil.LOGGER;
26 | import static com.ethanco.halo.turbo.mina.MinaUtil.convertToISession;
27 |
28 | /**
29 | * Mina Nio Tcp Server
30 | *
31 | * @author EthanCo
32 | * @since 2017/1/17
33 | */
34 |
35 | public class MinaUdpServerSocket extends AbstractSocket {
36 |
37 | private NioDatagramAcceptor acceptor;
38 | private InetSocketAddress address;
39 | private WifiManager.MulticastLock lock;
40 |
41 | public MinaUdpServerSocket(Config config) {
42 | super(config);
43 | }
44 |
45 | private void init(Config config) {
46 | address = new InetSocketAddress(config.sourcePort);
47 |
48 | acceptor = new NioDatagramAcceptor();
49 | acceptor.setHandler(new MinaServerHandler());
50 | DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
51 | if (acceptor.getFilterChain().get(LOGGER) == null) {
52 | chain.addLast(LOGGER, new LoggingFilter());
53 | }
54 | if (acceptor.getFilterChain().get(CODEC) == null) {
55 | ProtocolCodecFactory codecFactory = config.codec == null ?
56 | MinaUtil.getTextLineCodecFactory() : (ProtocolCodecFactory) config.codec;
57 | chain.addLast(CODEC, new ProtocolCodecFilter(codecFactory));
58 | }
59 | DatagramSessionConfig dcfg = acceptor.getSessionConfig();
60 | dcfg.setReuseAddress(true);
61 | dcfg.setReadBufferSize(config.bufferSize);
62 | dcfg.setIdleTime(IdleStatus.WRITER_IDLE, 10);
63 | dcfg.setBroadcast(true);
64 |
65 | KeepAliveFilter keepAliveFilter = MinaUtil.initServerKeepAlive(config, this);
66 | if (keepAliveFilter != null) {
67 | acceptor.getFilterChain().addLast(HEARTBEAT, keepAliveFilter);
68 | }
69 | }
70 |
71 |
72 | @Override
73 | public boolean start() {
74 | super.start();
75 | if (isRunning()) {
76 | return false;
77 | }
78 |
79 | Context context = config.context;
80 | if (context == null) {
81 | throw new IllegalArgumentException("context is null,please set context first.");
82 | }
83 |
84 | WifiManager manager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
85 | lock = manager.createMulticastLock("halo mina udp server");
86 |
87 | lock.acquire();
88 |
89 | init(config);
90 | try {
91 | acceptor.bind(address);
92 | } catch (IOException e) {
93 | e.printStackTrace();
94 | }
95 |
96 | onStartSuccess();
97 | lock.release();
98 | return true;
99 | }
100 |
101 | @Override
102 | public void stop() {
103 | super.stop();
104 | if (acceptor == null) {
105 | return;
106 | }
107 | if (acceptor.isDisposed() || acceptor.isDisposing()) {
108 | return;
109 | }
110 |
111 | acceptor.unbind(address);
112 | acceptor.dispose();
113 | acceptor = null;
114 | address = null;
115 |
116 | onStopped();
117 | }
118 |
119 | @Override
120 | public boolean isRunning() {
121 | if (acceptor == null) {
122 | return false;
123 | }
124 |
125 | return acceptor.isActive();
126 | }
127 |
128 | private class MinaServerHandler extends IoHandlerAdapter {
129 | @Override
130 | public void sessionCreated(IoSession session) throws Exception {
131 | super.sessionCreated(session);
132 | MinaUdpServerSocket.this.sessionCreated(convertToISession(session, MinaUdpServerSocket.this));
133 | }
134 |
135 | @Override
136 | public void sessionOpened(IoSession session) throws Exception {
137 | super.sessionOpened(session);
138 | MinaUdpServerSocket.this.sessionOpened(convertToISession(session, MinaUdpServerSocket.this));
139 | }
140 |
141 | @Override
142 | public void messageReceived(IoSession session, Object message) throws Exception {
143 | super.messageReceived(session, message);
144 | MinaUdpServerSocket.this.messageReceived(convertToISession(session, MinaUdpServerSocket.this), receive(message));
145 | }
146 |
147 | @Override
148 | public void messageSent(IoSession session, Object message) throws Exception {
149 | super.messageSent(session, message);
150 | //MinaServerSocket.this.messageSent(convertToISession(session, MinaServerSocket.this), message);
151 | }
152 |
153 | @Override
154 | public void sessionClosed(IoSession session) throws Exception {
155 | super.sessionClosed(session);
156 | MinaUdpServerSocket.this.sessionClosed(convertToISession(session, MinaUdpServerSocket.this));
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/ethanco/sample/MinaTcpClientByteActivity.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.text.TextUtils;
7 | import android.view.View;
8 | import android.widget.Toast;
9 |
10 | import com.ethanco.halo.turbo.Halo;
11 | import com.ethanco.halo.turbo.ads.IHandlerAdapter;
12 | import com.ethanco.halo.turbo.ads.ISession;
13 | import com.ethanco.halo.turbo.impl.handler.HexLogHandler;
14 | import com.ethanco.halo.turbo.type.Mode;
15 | import com.ethanco.halo.turbo.utils.HexUtil;
16 | import com.ethanco.sample.databinding.ActivityMinaTcpClientBinding;
17 |
18 | import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
19 |
20 | public class MinaTcpClientByteActivity extends AppCompatActivity {
21 |
22 | private static final String TAG = "Z-MinaTcpClientByteActivity";
23 | private ActivityMinaTcpClientBinding binding;
24 | private ScrollBottomTextWatcher watcher;
25 | private ISession session;
26 | private Halo halo;
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | binding = DataBindingUtil.setContentView(this, R.layout.activity_mina_tcp_client);
32 |
33 | binding.btnConnect.setOnClickListener(new View.OnClickListener() {
34 | @Override
35 | public void onClick(View v) {
36 | final String targetIP = binding.etTargetIp.getText().toString();
37 | if (TextUtils.isEmpty(targetIP)) {
38 | Toast.makeText(MinaTcpClientByteActivity.this, "目标IP不能为空", Toast.LENGTH_SHORT).show();
39 | }
40 |
41 | new Thread() {
42 | @Override
43 | public void run() {
44 | if (halo == null) {
45 | halo = new Halo.Builder()
46 | .setMode(Mode.MINA_NIO_TCP_CLIENT)
47 | .setBufferSize(2048)
48 | .setTargetIP(targetIP)
49 | .setTargetPort(19701)
50 | .addHandler(new HexLogHandler(TAG))
51 | .addHandler(new DemoHandler())
52 | .setCodec(new ObjectSerializationCodecFactory())
53 | .build();
54 | }
55 |
56 | if (halo.isRunning()) {
57 | runOnUiThread(new Runnable() {
58 | @Override
59 | public void run() {
60 | Toast.makeText(getApplication(), "已启动", Toast.LENGTH_SHORT).show();
61 | }
62 | });
63 | return;
64 | }
65 |
66 | final boolean startSuccess = halo.start();
67 | runOnUiThread(new Runnable() {
68 | @Override
69 | public void run() {
70 | String connectResult = startSuccess ? "连接成功" : "连接失败";
71 | binding.tvInfo.append(connectResult + "\r\n");
72 | }
73 | });
74 | }
75 | }.start();
76 | }
77 | });
78 |
79 | binding.btnSendData.setOnClickListener(new View.OnClickListener() {
80 | @Override
81 | public void onClick(View v) {
82 | if (session == null) {
83 | Toast.makeText(MinaTcpClientByteActivity.this, "未建立连接", Toast.LENGTH_SHORT).show();
84 | } else {
85 | //session.write("hello,这是从Client发送的数据");
86 | //session.write(new TestBean("aaa", "bbb"));
87 | session.write(new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06});
88 | }
89 | }
90 | });
91 |
92 | binding.btnStop.setOnClickListener(new View.OnClickListener() {
93 | @Override
94 | public void onClick(View v) {
95 | if (halo != null) {
96 | halo.stop();
97 | binding.tvInfo.append("停止连接" + "\r\n");
98 | }
99 | }
100 | });
101 |
102 | watcher = new ScrollBottomTextWatcher(binding.scrollView);
103 | binding.tvInfo.addTextChangedListener(watcher);
104 | }
105 |
106 | @Override
107 | protected void onDestroy() {
108 | super.onDestroy();
109 | if (watcher != null) {
110 | binding.tvInfo.removeTextChangedListener(watcher);
111 | watcher = null;
112 | }
113 | }
114 |
115 | class DemoHandler extends IHandlerAdapter {
116 |
117 | @Override
118 | public void sessionOpened(final ISession session) {
119 | MinaTcpClientByteActivity.this.session = session;
120 | //session.write("hello aaabbb");
121 | }
122 |
123 | @Override
124 | public void messageReceived(ISession session, Object message) {
125 | super.messageReceived(session, message);
126 | printInfo("接收:", message);
127 | }
128 |
129 | @Override
130 | public void messageSent(ISession session, Object message) {
131 | super.messageSent(session, message);
132 | printInfo("发送:", message);
133 | }
134 |
135 | @Override
136 | public void sessionClosed(ISession session) {
137 | super.sessionClosed(session);
138 | MinaTcpClientByteActivity.this.session = null;
139 | }
140 | }
141 |
142 | private void printInfo(String operation, Object message) {
143 | if (message instanceof byte[] || message instanceof Byte[]) {
144 | binding.tvInfo.append(operation + HexUtil.bytesToHexString((byte[]) message) + "\r\n");
145 | } else {
146 | binding.tvInfo.append(operation + message + "\r\n");
147 | }
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/halo-turbo-mina/src/main/java/com/ethanco/halo/turbo/mina/MinaUdpClientSocket.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.mina;
2 |
3 | import android.content.Context;
4 | import android.net.wifi.WifiManager;
5 |
6 | import com.ethanco.halo.turbo.ads.AbstractSocket;
7 | import com.ethanco.halo.turbo.bean.Config;
8 |
9 | import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
10 | import org.apache.mina.core.future.ConnectFuture;
11 | import org.apache.mina.core.future.IoFuture;
12 | import org.apache.mina.core.future.IoFutureListener;
13 | import org.apache.mina.core.service.IoHandlerAdapter;
14 | import org.apache.mina.core.session.IdleStatus;
15 | import org.apache.mina.core.session.IoSession;
16 | import org.apache.mina.filter.codec.ProtocolCodecFactory;
17 | import org.apache.mina.filter.codec.ProtocolCodecFilter;
18 | import org.apache.mina.filter.keepalive.KeepAliveFilter;
19 | import org.apache.mina.filter.logging.LoggingFilter;
20 | import org.apache.mina.transport.socket.nio.NioDatagramConnector;
21 |
22 | import java.net.InetAddress;
23 | import java.net.InetSocketAddress;
24 |
25 | import static com.ethanco.halo.turbo.mina.MinaUtil.CODEC;
26 | import static com.ethanco.halo.turbo.mina.MinaUtil.HEARTBEAT;
27 | import static com.ethanco.halo.turbo.mina.MinaUtil.LOGGER;
28 | import static com.ethanco.halo.turbo.mina.MinaUtil.convertToISession;
29 |
30 | /**
31 | * Mina Nio Tcp Socket
32 | *
33 | * @author EthanCo
34 | * @since 2017/1/17
35 | */
36 |
37 | public class MinaUdpClientSocket extends AbstractSocket {
38 | private InetSocketAddress address;
39 | private NioDatagramConnector connector;
40 | private WifiManager.MulticastLock lock;
41 |
42 | public MinaUdpClientSocket(Config config) {
43 | super(config);
44 | }
45 |
46 | private void init(Config config) {
47 | connector = new NioDatagramConnector();
48 | connector.setHandler(new MinaClientHandler());
49 | DefaultIoFilterChainBuilder chain = connector.getFilterChain();
50 | if (connector.getFilterChain().get(LOGGER) == null) {
51 | chain.addLast(LOGGER, new LoggingFilter());
52 | }
53 | if (connector.getFilterChain().get(CODEC) == null) {
54 | ProtocolCodecFactory codecFactory = config.codec == null ?
55 | MinaUtil.getTextLineCodecFactory() : (ProtocolCodecFactory) config.codec;
56 | chain.addLast(CODEC, new ProtocolCodecFilter(codecFactory));
57 | }
58 | connector.getSessionConfig().setReadBufferSize(config.bufferSize);
59 |
60 | connector.getSessionConfig().setIdleTime(IdleStatus.WRITER_IDLE, 10);
61 | connector.getSessionConfig().setBroadcast(true);
62 | KeepAliveFilter keepAliveFilter = MinaUtil.initClientKeepAlive(config, this);
63 | if (keepAliveFilter != null) {
64 | connector.getFilterChain().addLast(HEARTBEAT, keepAliveFilter);
65 | }
66 | }
67 |
68 | @Override
69 | public boolean start() {
70 | super.start();
71 | if (isRunning()) {
72 | return false;
73 | }
74 |
75 | Context context = config.context;
76 | if (context == null) {
77 | throw new IllegalArgumentException("context is null,please set context first.");
78 | }
79 |
80 | WifiManager manager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
81 | lock = manager.createMulticastLock("halo mina udp client");
82 |
83 | lock.acquire();
84 |
85 | init(config);
86 | InetSocketAddress remoteAddress = new InetSocketAddress(config.targetIP, config.targetPort);
87 | InetSocketAddress localAddress = null;
88 | try {
89 | InetAddress localIP = MinaUtil.getLocalHostLANAddress();
90 | localAddress = new InetSocketAddress(localIP, config.sourcePort);
91 | } catch (Exception e) {
92 | e.printStackTrace();
93 | }
94 |
95 | ConnectFuture future;
96 | if (localAddress != null) {
97 | future = connector.connect(remoteAddress, localAddress);
98 | }else{
99 | future = connector.connect(remoteAddress);
100 | }
101 | future.awaitUninterruptibly();
102 | future.addListener(new IoFutureListener() {
103 | public void operationComplete(IoFuture future) {
104 | ConnectFuture connFuture = (ConnectFuture) future;
105 | if (connFuture.isConnected()) {
106 | synchronized (MinaUdpClientSocket.this) {
107 | session = MinaUtil.convertToISession(future.getSession(), MinaUdpClientSocket.this);
108 | onStartSuccess();
109 | }
110 | } else {
111 | onStartFailed(new Exception("Not connected...exiting"));
112 | }
113 | }
114 | });
115 |
116 | lock.release();
117 | return true;
118 | //return mSession == null ? false : true;
119 | }
120 |
121 | @Override
122 | public void stop() {
123 | super.stop();
124 | if (connector == null) {
125 | return;
126 | }
127 | if (connector.isDisposed() || connector.isDisposing()) {
128 | return;
129 | }
130 |
131 | connector.dispose();
132 | connector = null;
133 | address = null;
134 | onStopped();
135 | }
136 |
137 | @Override
138 | public boolean isRunning() {
139 | if (connector == null) {
140 | return false;
141 | }
142 | return connector.isActive();
143 | }
144 |
145 | private class MinaClientHandler extends IoHandlerAdapter {
146 | @Override
147 | public void sessionCreated(IoSession session) throws Exception {
148 | super.sessionCreated(session);
149 | //MinaUdpClientSocket.this.sessionCreated(convertToISession(session, MinaUdpClientSocket.this));
150 | }
151 |
152 | @Override
153 | public void sessionOpened(IoSession session) throws Exception {
154 | super.sessionOpened(session);
155 | MinaUdpClientSocket.this.sessionOpened(convertToISession(session, MinaUdpClientSocket.this));
156 | }
157 |
158 | @Override
159 | public void messageReceived(IoSession session, Object message) throws Exception {
160 | super.messageReceived(session, message);
161 | MinaUdpClientSocket.this.messageReceived(convertToISession(session, MinaUdpClientSocket.this), receive(message));
162 | }
163 |
164 | @Override
165 | public void messageSent(IoSession session, Object message) throws Exception {
166 | super.messageSent(session, message);
167 | //Log.i("Z-Test", "messageSent:" + message);
168 | //MinaClientSocket.this.messageSent(convertToISession(session, MinaClientSocket.this), message);
169 | }
170 |
171 | @Override
172 | public void sessionClosed(IoSession session) throws Exception {
173 | super.sessionClosed(session);
174 | MinaUdpClientSocket.this.sessionClosed(convertToISession(session, MinaUdpClientSocket.this));
175 | }
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | Android
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | 1.8
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/ethanco/sample/MinaTcpClientHeartBeatActivity.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.sample;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.text.TextUtils;
7 | import android.util.Log;
8 | import android.view.View;
9 | import android.widget.Toast;
10 |
11 | import com.ethanco.halo.turbo.Halo;
12 | import com.ethanco.halo.turbo.ads.IHandlerAdapter;
13 | import com.ethanco.halo.turbo.ads.IKeepAliveListener;
14 | import com.ethanco.halo.turbo.ads.ISession;
15 | import com.ethanco.halo.turbo.bean.KeepAlive;
16 | import com.ethanco.halo.turbo.impl.handler.StringLogHandler;
17 | import com.ethanco.halo.turbo.type.Mode;
18 | import com.ethanco.json.convertor.convert.ObjectJsonConvertor;
19 | import com.ethanco.sample.databinding.ActivityMinaTcpClientBinding;
20 |
21 | import static com.ethanco.sample.MinaTcpServerHeartBeatActivity.HEART_BEAT;
22 |
23 | public class MinaTcpClientHeartBeatActivity extends AppCompatActivity {
24 |
25 | private static final String TAG = "Z-MinaTcpClientActivity";
26 | private static final String TAG2 = "Z-KeepAlive";
27 | private ActivityMinaTcpClientBinding binding;
28 | private ScrollBottomTextWatcher watcher;
29 | private ISession session;
30 | private Halo halo;
31 |
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | binding = DataBindingUtil.setContentView(this, R.layout.activity_mina_tcp_client);
36 |
37 | binding.btnConnect.setOnClickListener(new View.OnClickListener() {
38 | @Override
39 | public void onClick(View v) {
40 | final String targetIP = binding.etTargetIp.getText().toString();
41 | if (TextUtils.isEmpty(targetIP)) {
42 | Toast.makeText(MinaTcpClientHeartBeatActivity.this, "目标IP不能为空", Toast.LENGTH_SHORT).show();
43 | }
44 |
45 | new Thread() {
46 | @Override
47 | public void run() {
48 | if (halo == null) {
49 | halo = new Halo.Builder()
50 | .setMode(Mode.MINA_NIO_TCP_CLIENT)
51 | .setBufferSize(2048)
52 | .setTargetIP(targetIP)
53 | .setTargetPort(19701)
54 | .addHandler(new StringLogHandler(TAG))
55 | .addHandler(new DemoHandler())
56 | .addConvert(new ObjectJsonConvertor()) //增加转换器 -> write的时候自动转换为Json字符串
57 | .setKeepAlive(new KeepAlive(15, 60, keepAliveListener))
58 | .build();
59 | }
60 |
61 | if (halo.isRunning()) {
62 | runOnUiThread(new Runnable() {
63 | @Override
64 | public void run() {
65 | Toast.makeText(getApplication(), "已启动", Toast.LENGTH_SHORT).show();
66 | }
67 | });
68 | return;
69 | }
70 |
71 | final boolean startSuccess = halo.start();
72 | runOnUiThread(new Runnable() {
73 | @Override
74 | public void run() {
75 | String connectResult = startSuccess ? "连接成功" : "连接失败";
76 | binding.tvInfo.append(connectResult + "\r\n");
77 | }
78 | });
79 | }
80 | }.start();
81 | }
82 | });
83 |
84 | binding.btnSendData.setOnClickListener(new View.OnClickListener() {
85 | @Override
86 | public void onClick(View v) {
87 | if (session == null) {
88 | Toast.makeText(MinaTcpClientHeartBeatActivity.this, "未建立连接", Toast.LENGTH_SHORT).show();
89 | } else {
90 | //session.write("hello,这是从Client发送的数据");
91 | session.write(new TestBean("aaa", "bbb"));
92 | }
93 | }
94 | });
95 |
96 | binding.btnStop.setOnClickListener(new View.OnClickListener() {
97 | @Override
98 | public void onClick(View v) {
99 | if (halo != null) {
100 | halo.stop();
101 | binding.tvInfo.append("停止连接" + "\r\n");
102 | }
103 | }
104 | });
105 |
106 | watcher = new ScrollBottomTextWatcher(binding.scrollView);
107 | binding.tvInfo.addTextChangedListener(watcher);
108 | }
109 |
110 | @Override
111 | protected void onDestroy() {
112 | super.onDestroy();
113 | if (watcher != null) {
114 | binding.tvInfo.removeTextChangedListener(watcher);
115 | watcher = null;
116 | }
117 | }
118 |
119 | class DemoHandler extends IHandlerAdapter {
120 |
121 | @Override
122 | public void sessionOpened(final ISession session) {
123 | Log.i(TAG2, "sessionOpened : ");
124 | MinaTcpClientHeartBeatActivity.this.session = session;
125 | //session.write("hello aaabbb");
126 | }
127 |
128 | @Override
129 | public void messageReceived(ISession session, Object message) {
130 | Log.i(TAG2, "messageReceived : ");
131 | String receive = String.valueOf(message);
132 | binding.tvInfo.append("接收:" + receive + "\r\n");
133 | }
134 |
135 | @Override
136 | public void messageSent(ISession session, Object message) {
137 | Log.i(TAG2, "messageSent : ");
138 | super.messageSent(session, message);
139 | binding.tvInfo.append("发送:" + message + "\r\n");
140 | }
141 |
142 | @Override
143 | public void sessionClosed(ISession session) {
144 | super.sessionClosed(session);
145 | Log.i(TAG2, "sessionClosed : ");
146 | MinaTcpClientHeartBeatActivity.this.session = null;
147 | }
148 |
149 | @Override
150 | public void sessionCreated(ISession session) {
151 | Log.i(TAG2, "sessionCreated : ");
152 | super.sessionCreated(session);
153 | }
154 | }
155 |
156 | private IKeepAliveListener keepAliveListener = new IKeepAliveListener() {
157 | @Override
158 | public void onKeepAliveRequestTimedOut(KeepAlive keepAlive, ISession iSession) {
159 | Log.i(TAG2, "Client >>> onKeepAliveRequestTimedOut...:" + iSession);
160 | }
161 |
162 | @Override
163 | public boolean isKeepAliveMessage(ISession ioSession, Object message) {
164 | if (message == null) return false;
165 | if (message instanceof String) {
166 | return message.equals(HEART_BEAT);
167 | }
168 | return false;
169 | }
170 |
171 | @Override
172 | public Object getKeepAliveMessage(ISession ioSession, Object o) {
173 | return HEART_BEAT;
174 | }
175 | };
176 | }
177 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/utils/HexUtil.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.utils;
2 |
3 | /**
4 | * Description
5 | * Created by chenqiao on 2015/8/17.
6 | */
7 | public class HexUtil {
8 | /**
9 | * byte数组中取int数值,本方法适用于(低位在后,高位在前)的顺序。和intToBytes2()配套使用
10 | */
11 | public static int bytesToInt(byte[] src, int offset) {
12 | int value;
13 | value = (int) ( ((src[offset] & 0xFF)<<24)
14 | |((src[offset+1] & 0xFF)<<16)
15 | |((src[offset+2] & 0xFF)<<8)
16 | |(src[offset+3] & 0xFF));
17 | return value;
18 | }
19 |
20 | /**
21 | * 字符串转换成十六进制字符串
22 | *
23 | * @param str 待转换的ASCII字符串
24 | * @return String 每个Byte之间空格分隔,如: [61 6C 6B]
25 | */
26 | public static String str2HexStr(String str) {
27 |
28 | char[] chars = "0123456789ABCDEF".toCharArray();
29 | StringBuilder sb = new StringBuilder("");
30 | byte[] bs = str.getBytes();
31 | int bit;
32 |
33 | for (int i = 0; i < bs.length; i++) {
34 | bit = (bs[i] & 0x0f0) >> 4;
35 | sb.append(chars[bit]);
36 | bit = bs[i] & 0x0f;
37 | sb.append(chars[bit]);
38 | sb.append(' ');
39 | }
40 | return sb.toString().trim();
41 | }
42 |
43 | /**
44 | * 十六进制转换字符串
45 | *
46 | * @param hexStr Byte字符串(Byte之间无分隔符 如:[616C6B])
47 | * @return String 对应的字符串
48 | */
49 | public static String hexStr2Str(String hexStr) {
50 | String str = "0123456789ABCDEF";
51 | char[] hexs = hexStr.toCharArray();
52 | byte[] bytes = new byte[hexStr.length() / 2];
53 | int n;
54 |
55 | for (int i = 0; i < bytes.length; i++) {
56 | n = str.indexOf(hexs[2 * i]) * 16;
57 | n += str.indexOf(hexs[2 * i + 1]);
58 | bytes[i] = (byte) (n & 0xff);
59 | }
60 | return new String(bytes);
61 | }
62 |
63 | /**
64 | * bytes转换成十六进制字符串 - 有空格
65 | *
66 | * @param src byte数组
67 | * @return String
68 | */
69 | public static String bytesToHexString(byte[] src) {
70 | StringBuilder stringBuilder = new StringBuilder("");
71 | if (src == null || src.length <= 0) {
72 | return null;
73 | }
74 | for (int i = 0; i < src.length; i++) {
75 | int v = src[i] & 0xFF;
76 | String hv = Integer.toHexString(v);
77 | if (hv.length() < 2) {
78 | stringBuilder.append(0);
79 | }
80 | stringBuilder.append(hv + " ");
81 | }
82 | return stringBuilder.toString();
83 | }
84 |
85 | /**
86 | * bytes转换成十六进制字符串 - 没有空格
87 | *
88 | * @param src byte数组
89 | * @return String
90 | */
91 | public static String bytesToHexStringNoSpace(byte[] src) {
92 | StringBuilder stringBuilder = new StringBuilder("");
93 | if (src == null || src.length <= 0) {
94 | return null;
95 | }
96 | for (int i = 0; i < src.length; i++) {
97 | int v = src[i] & 0xFF;
98 | String hv = Integer.toHexString(v);
99 | if (hv.length() < 2) {
100 | stringBuilder.append(0);
101 | }
102 | stringBuilder.append(hv);
103 | }
104 | return stringBuilder.toString();
105 | }
106 |
107 | /**
108 | * bytes字符串转换为Byte值
109 | *
110 | * @param hexString Byte字符串,每个Byte之间没有分隔符
111 | * @return byte[]
112 | */
113 | public static byte[] hexStr2Bytes(String hexString) {
114 | if (hexString == null || hexString.equals("")) {
115 | return null;
116 | }
117 | hexString = hexString.toUpperCase();
118 | int length = hexString.length() / 2;
119 | char[] hexChars = hexString.toCharArray();
120 | byte[] d = new byte[length];
121 | for (int i = 0; i < length; i++) {
122 | int pos = i * 2;
123 | d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
124 | }
125 | return d;
126 | }
127 |
128 | private static byte charToByte(char c) {
129 | return (byte) "0123456789ABCDEF".indexOf(c);
130 | }
131 |
132 | /**
133 | * String的字符串转换成unicode的String
134 | *
135 | * @param strText 全角字符串
136 | * @return String 每个unicode之间无分隔符
137 | * @throws Exception
138 | */
139 | public static String strToUnicode(String strText) throws Exception {
140 | char c;
141 | StringBuilder str = new StringBuilder();
142 | int intAsc;
143 | String strHex;
144 | for (int i = 0; i < strText.length(); i++) {
145 | c = strText.charAt(i);
146 | intAsc = (int) c;
147 | strHex = Integer.toHexString(intAsc);
148 | if (intAsc > 128)
149 | str.append("\\u" + strHex);
150 | else
151 | // 低位在前面补00
152 | str.append("\\u00" + strHex);
153 | }
154 | return str.toString();
155 | }
156 |
157 | /**
158 | * unicode的String转换成String的字符串
159 | *
160 | * @param hex 16进制值字符串 (一个unicode为2byte)
161 | * @return String 全角字符串
162 | */
163 | public static String unicodeToString(String hex) {
164 | int t = hex.length() / 6;
165 | StringBuilder str = new StringBuilder();
166 | for (int i = 0; i < t; i++) {
167 | String s = hex.substring(i * 6, (i + 1) * 6);
168 | // 高位需要补上00再转
169 | String s1 = s.substring(2, 4) + "00";
170 | // 低位直接转
171 | String s2 = s.substring(4);
172 | // 将16进制的string转为int
173 | int n = Integer.valueOf(s1, 16) + Integer.valueOf(s2, 16);
174 | // 将int转换为字符
175 | char[] chars = Character.toChars(n);
176 | str.append(new String(chars));
177 | }
178 | return str.toString();
179 | }
180 |
181 | /**
182 | * 转换short为byte
183 | *
184 | * @param b
185 | * @param s 需要转换的short
186 | * @param index
187 | */
188 | public static void putShort(byte b[], short s, int index) {
189 | b[index + 1] = (byte) (s >> 8);
190 | b[index + 0] = (byte) (s >> 0);
191 | }
192 |
193 | /**
194 | * 转换short为byte (高位在前)
195 | *
196 | * @param b
197 | * @param s 需要转换的short
198 | * @param index
199 | */
200 | public static void putShortHighBefore(byte b[], short s, int index) {
201 | b[index + 0] = (byte) (s >> 8);
202 | b[index + 1] = (byte) (s >> 0);
203 | }
204 |
205 | /**
206 | * 合并数组
207 | *
208 | * @param a 合并的数组1(在前)
209 | * @param b 合并的数组2(在后)
210 | * @return
211 | */
212 | public static byte[] mergeArray(byte a[], byte b[]) {
213 | byte[] mergeArr = new byte[a.length + b.length];
214 | System.arraycopy(a, 0, mergeArr, 0, a.length);
215 | System.arraycopy(b, 0, mergeArr, a.length, b.length);
216 | return mergeArr;
217 | }
218 | /**
219 | * 合并数组
220 | *
221 | * @param a 合并的数组1(在前)
222 | * @param b 合并的数组2(在后)
223 | * @return
224 | */
225 | public static String[] mergeArray(String a[], String b[]) {
226 | String[] mergeArr = new String[a.length + b.length];
227 | System.arraycopy(a, 0, mergeArr, 0, a.length);
228 | System.arraycopy(b, 0, mergeArr, a.length, b.length);
229 | return mergeArr;
230 | }
231 | }
--------------------------------------------------------------------------------
/halo-turbo-mina/src/main/java/com/ethanco/halo/turbo/mina/MinaTcpClientSocket.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.mina;
2 |
3 | import android.os.SystemClock;
4 |
5 | import com.ethanco.halo.turbo.ads.AbstractSocket;
6 | import com.ethanco.halo.turbo.bean.Config;
7 | import com.ethanco.halo.turbo.bean.KeepAlive;
8 |
9 | import org.apache.mina.core.future.ConnectFuture;
10 | import org.apache.mina.core.service.IoHandlerAdapter;
11 | import org.apache.mina.core.session.IdleStatus;
12 | import org.apache.mina.core.session.IoSession;
13 | import org.apache.mina.filter.codec.ProtocolCodecFactory;
14 | import org.apache.mina.filter.codec.ProtocolCodecFilter;
15 | import org.apache.mina.filter.keepalive.KeepAliveFilter;
16 | import org.apache.mina.filter.logging.LoggingFilter;
17 | import org.apache.mina.transport.socket.nio.NioSocketConnector;
18 |
19 | import java.net.InetSocketAddress;
20 | import java.util.concurrent.ExecutorService;
21 |
22 | import static com.ethanco.halo.turbo.mina.MinaUtil.CODEC;
23 | import static com.ethanco.halo.turbo.mina.MinaUtil.HEARTBEAT;
24 | import static com.ethanco.halo.turbo.mina.MinaUtil.LOGGER;
25 | import static com.ethanco.halo.turbo.mina.MinaUtil.convertToISession;
26 |
27 | /**
28 | * Mina Nio Tcp Socket
29 | *
30 | * @author EthanCo
31 | * @since 2017/1/17
32 | */
33 |
34 | public class MinaTcpClientSocket extends AbstractSocket {
35 | private InetSocketAddress address;
36 | private NioSocketConnector connector;
37 | private IoSession mSession;
38 | private volatile boolean isAutoReConn = true;
39 | private boolean isClosed = false;
40 |
41 | public MinaTcpClientSocket(Config config) {
42 | super(config);
43 | }
44 |
45 | private void init(Config config) {
46 | address = new InetSocketAddress(config.targetIP, config.targetPort);
47 | connector = new NioSocketConnector();
48 | connector.setDefaultRemoteAddress(address);
49 | if (connector.getFilterChain().get(LOGGER) == null) {
50 | connector.getFilterChain().addLast(LOGGER, new LoggingFilter());
51 | }
52 | if (connector.getFilterChain().get(CODEC) == null) {
53 | ProtocolCodecFactory codecFactory = config.codec == null ?
54 | MinaUtil.getTextLineCodecFactory() : (ProtocolCodecFactory) config.codec;
55 | connector.getFilterChain().addLast(CODEC, new ProtocolCodecFilter(codecFactory));
56 | }
57 | connector.setHandler(new MinaClientHandler());
58 | connector.getSessionConfig().setReadBufferSize(config.bufferSize);
59 | connector.getSessionConfig().setIdleTime(IdleStatus.WRITER_IDLE, 10);
60 | KeepAliveFilter keepAliveFilter = MinaUtil.initClientKeepAlive(config, this);
61 | if (keepAliveFilter != null) {
62 | connector.getFilterChain().addLast(HEARTBEAT, keepAliveFilter);
63 | }
64 | }
65 |
66 | @Override
67 | public boolean start() {
68 | super.start();
69 | isAutoReConn = true;
70 | if (isRunning()) {
71 | return false;
72 | }
73 |
74 | init(config);
75 | ConnectFuture future = connector.connect();
76 | future.awaitUninterruptibly();
77 | try {
78 | mSession = future.getSession();
79 | } catch (Exception e) {
80 | onStartFailed(e);
81 | return false;
82 | }
83 |
84 | onStartSuccess();
85 | return true;
86 | //return mSession == null ? false : true;
87 | }
88 |
89 | @Override
90 | public void stop() {
91 | super.stop();
92 | isAutoReConn = false;
93 | if (connector == null) {
94 | return;
95 | }
96 | if (connector.isDisposed() || connector.isDisposing()) {
97 | return;
98 | }
99 |
100 | connector.dispose();
101 | connector = null;
102 | mSession = null;
103 | address = null;
104 | onStopped();
105 | }
106 |
107 | @Override
108 | public boolean isRunning() {
109 | if (connector == null) {
110 | return false;
111 | }
112 | return connector.isActive() && !isClosed;
113 | }
114 |
115 | private class MinaClientHandler extends IoHandlerAdapter {
116 | @Override
117 | public void sessionCreated(IoSession session) throws Exception {
118 | super.sessionCreated(session);
119 | MinaTcpClientSocket.this.sessionCreated(convertToISession(session, MinaTcpClientSocket.this));
120 | }
121 |
122 | @Override
123 | public void sessionOpened(IoSession session) throws Exception {
124 | super.sessionOpened(session);
125 | isClosed = false;
126 | MinaTcpClientSocket.this.sessionOpened(convertToISession(session, MinaTcpClientSocket.this));
127 | }
128 |
129 | @Override
130 | public void messageReceived(IoSession session, Object message) throws Exception {
131 | super.messageReceived(session, message);
132 | MinaTcpClientSocket.this.messageReceived(convertToISession(session, MinaTcpClientSocket.this), receive(message));
133 | }
134 |
135 | @Override
136 | public void messageSent(IoSession session, Object message) throws Exception {
137 | super.messageSent(session, message);
138 | //Log.i("Z-Test", "messageSent:" + message);
139 | //MinaClientSocket.this.messageSent(convertToISession(session, MinaClientSocket.this), message);
140 | }
141 |
142 | @Override
143 | public void sessionClosed(IoSession session) throws Exception {
144 | super.sessionClosed(session);
145 | isClosed = true;
146 | MinaTcpClientSocket.this.sessionClosed(convertToISession(session, MinaTcpClientSocket.this));
147 |
148 | //断线重连 详见:https://my.oschina.net/yjwxh/blog/174633
149 | synchronized (this) {
150 |
151 | if (!isAutoReConn) return;
152 | if (isRunning()) return;
153 | ExecutorService threadPool = config.threadPool;
154 | final KeepAlive keepAlive = config.keepAlive;
155 | if (keepAlive != null) return; //如果keepAlive不为NULL,则交由keepAlive进行重连处理
156 |
157 | threadPool.execute(new Runnable() {
158 | @Override
159 | public void run() {
160 | boolean reConn = isAutoReConn && !isRunning();
161 | System.out.println("开始重连 reConn:" + reConn);
162 | do {
163 | try {
164 | onReConnecting();
165 | MinaTcpClientSocket.this.stop();
166 |
167 | init(config);
168 | MinaTcpClientSocket.this.start();
169 | onReConnected();
170 | int reConnTime = keepAlive == null ? 10 * 1000 : keepAlive.getReConnTime();
171 | System.out.println("开始重连-->Sleep:" + reConnTime);
172 | SystemClock.sleep(reConnTime);
173 | reConn = isAutoReConn && !isRunning();
174 | System.out.println("开始重连--->reConn:" + reConn);
175 | } catch (Exception e) {
176 | onReConnectFailed(e);
177 | }
178 | } while (reConn);
179 | }
180 | });
181 | }
182 | }
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/halo-turbo/src/main/java/com/ethanco/halo/turbo/ads/AbstractSocket.java:
--------------------------------------------------------------------------------
1 | package com.ethanco.halo.turbo.ads;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 |
6 | import com.ethanco.halo.turbo.bean.Config;
7 | import com.ethanco.halo.turbo.impl.convert.ConvertManager;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | /**
13 | * Created by EthanCo on 2016/9/16.
14 | */
15 | public abstract class AbstractSocket implements ISocket, ILog {
16 | protected Config config;
17 | protected ISession session = null;
18 | protected List handlers = new ArrayList<>();
19 | protected Handler M = new Handler(Looper.getMainLooper());
20 | protected ConvertManager convertManager;
21 |
22 | public AbstractSocket(Config config) {
23 | this.config = config;
24 | convertManager = new ConvertManager(config.convertors);
25 | addAllHandler();
26 | getHandlers();
27 | }
28 |
29 | @Override
30 | public boolean start() {
31 | onStarting();
32 | return false;
33 | }
34 |
35 | @Override
36 | public void stop() {
37 | onStopping();
38 | M.removeCallbacksAndMessages(null);
39 | }
40 |
41 | private void addAllHandler() {
42 | if (config.handlers != null) {
43 | for (IHandler handler : config.handlers) {
44 | if (handler instanceof AbstractLog) {
45 | AbstractLog logHandler = (AbstractLog) (handler);
46 | logHandler.setPrefix(getSimpleName());
47 | }
48 | }
49 |
50 | handlers.addAll(config.handlers);
51 | }
52 | }
53 |
54 | @Override
55 | public List getHandlers() {
56 | return handlers;
57 | }
58 |
59 | @Override
60 | public void addHandler(IHandler handler) {
61 | if (handler == null) return;
62 |
63 | if (!handlers.contains(handler)) {
64 | handlers.add(handler);
65 | }
66 | }
67 |
68 | @Override
69 | public boolean removeHandler(IHandler handler) {
70 | return handlers.remove(handler);
71 | }
72 |
73 | protected String getSimpleName() {
74 | return getClass().getSimpleName();
75 | }
76 |
77 | public Object convert(Object message) {
78 | if (convertManager != null) {
79 | Object convertData = convertManager.convert(message);
80 | //Log.i("Z-Test", "convert" + convertData);
81 | return convertData;
82 | }
83 | return message;
84 | }
85 |
86 | protected Object receive(Object message) {
87 | if (convertManager != null) {
88 | return convertManager.receive(message);
89 | }
90 |
91 | return message;
92 | }
93 |
94 | @Override
95 | public void sessionCreated(final ISession session) {
96 | M.post(new Runnable() {
97 | @Override
98 | public void run() {
99 | for (IHandler handler : handlers) {
100 | if (handler != null) {
101 | handler.sessionCreated(session);
102 | }
103 | }
104 | }
105 | });
106 | }
107 |
108 | @Override
109 | public void sessionOpened(final ISession session) {
110 | M.post(new Runnable() {
111 | @Override
112 | public void run() {
113 | for (IHandler handler : handlers) {
114 | if (handler != null) {
115 | handler.sessionOpened(session);
116 | }
117 | }
118 | }
119 | });
120 | }
121 |
122 | @Override
123 | public void sessionClosed(final ISession session) {
124 | M.post(new Runnable() {
125 | @Override
126 | public void run() {
127 | for (IHandler handler : handlers) {
128 | if (handler != null) {
129 | handler.sessionClosed(session);
130 | }
131 | }
132 | }
133 | });
134 | }
135 |
136 | @Override
137 | public void messageReceived(final ISession session, final Object message) {
138 | M.post(new Runnable() {
139 | @Override
140 | public void run() {
141 | for (IHandler handler : handlers) {
142 | if (handler != null) {
143 | handler.messageReceived(session, message);
144 | }
145 | }
146 | }
147 | });
148 | }
149 |
150 | @Override
151 | public void messageSent(final ISession session, final Object message) {
152 | M.post(new Runnable() {
153 | @Override
154 | public void run() {
155 | for (IHandler handler : handlers) {
156 | if (handler != null) {
157 | handler.messageSent(session, message);
158 | }
159 | }
160 | }
161 | });
162 | }
163 |
164 | @Override
165 | public void onStarting() {
166 | execLog(new LogListener() {
167 | @Override
168 | public void onExec(ILog log) {
169 | log.onStarting();
170 | }
171 | });
172 | }
173 |
174 | @Override
175 | public void onStartSuccess() {
176 | execLog(new LogListener() {
177 | @Override
178 | public void onExec(ILog log) {
179 | log.onStartSuccess();
180 | }
181 | });
182 | }
183 |
184 | @Override
185 | public void onStartFailed(final Exception e) {
186 | execLog(new LogListener() {
187 | @Override
188 | public void onExec(ILog log) {
189 | log.onStartFailed(e);
190 | }
191 | });
192 | }
193 |
194 | @Override
195 | public void onStopping() {
196 | execLog(new LogListener() {
197 | @Override
198 | public void onExec(ILog log) {
199 | log.onStopping();
200 | }
201 | });
202 | }
203 |
204 | @Override
205 | public void onStopped() {
206 | execLog(new LogListener() {
207 | @Override
208 | public void onExec(ILog log) {
209 | log.onStopped();
210 | }
211 | });
212 | }
213 |
214 | @Override
215 | public void onReceiveException(final Exception e) {
216 | execLog(new LogListener() {
217 | @Override
218 | public void onExec(ILog log) {
219 | log.onReceiveException(e);
220 | }
221 | });
222 | }
223 |
224 | @Override
225 | public void onReConnecting() {
226 | execLog(new LogListener() {
227 | @Override
228 | public void onExec(ILog log) {
229 | log.onReConnecting();
230 | }
231 | });
232 | }
233 |
234 | @Override
235 | public void onReConnected() {
236 | execLog(new LogListener() {
237 | @Override
238 | public void onExec(ILog log) {
239 | log.onReConnected();
240 | }
241 | });
242 | }
243 |
244 | @Override
245 | public void onReConnectFailed(final Exception e) {
246 | execLog(new LogListener() {
247 | @Override
248 | public void onExec(ILog log) {
249 | log.onReConnectFailed(e);
250 | }
251 | });
252 | }
253 |
254 | public interface LogListener {
255 | void onExec(ILog log);
256 | }
257 |
258 | public void execLog(final LogListener logListener) {
259 | M.post(new Runnable() {
260 | @Override
261 | public void run() {
262 | for (IHandler handler : handlers) {
263 | if (handler instanceof ILog) {
264 | ILog log = (ILog) handler;
265 | logListener.onExec(log);
266 | }
267 | }
268 | }
269 | });
270 | }
271 |
272 | @Override
273 | public String toString() {
274 | return getClass().getSimpleName();
275 | }
276 | }
277 |
--------------------------------------------------------------------------------