(this, android.R.layout.simple_spinner_item, mList);
62 | //设置样式
63 | arr_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
64 | //加载适配器
65 | spMode.setAdapter(arr_adapter);
66 |
67 | Gson gson = new Gson();
68 | TestBean codeGetModel = new TestBean();
69 | codeGetModel.protver = "100";
70 | codeGetModel.pkgtype = 1;
71 | codeGetModel.command = 15;
72 | codeGetModel.seq = 1000;
73 | TestBean.Inform in = codeGetModel.body;
74 | in.cmd = type;
75 | in.Phone = "18500000000";
76 | final String json = gson.toJson(codeGetModel);
77 | // bean转字符串并发送
78 | reDataStr = json + "\r\n";
79 | Log.i(TAG, "reDataStr-->" + reDataStr);
80 | tvRequest.setText(json);
81 | }
82 |
83 | private void initListener() {
84 | spMode.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
85 | @Override
86 | public void onItemSelected(AdapterView> parent, View view, int position, long id) {
87 | String str = mList.get(position).toString().trim();
88 | if (str.equals("auto")) {
89 | Socketer.getInstance(MainActivity.this).setParseMode(ParseMode.AUTO_PARSE);
90 | parseMode = ParseMode.AUTO_PARSE;
91 | } else if (str.equals("manually")) {
92 | Socketer.getInstance(MainActivity.this).setParseMode(ParseMode.MANUALLY_PARSE);
93 | parseMode = ParseMode.MANUALLY_PARSE;
94 | }
95 | }
96 |
97 | @Override
98 | public void onNothingSelected(AdapterView> parent) {
99 | Socketer.getInstance(MainActivity.this).setParseMode(ParseMode.AUTO_PARSE);
100 | parseMode = ParseMode.AUTO_PARSE;
101 | }
102 |
103 | });
104 |
105 | btSend.setOnClickListener(new View.OnClickListener() {
106 | @Override
107 | public void onClick(View v) {
108 | switch (parseMode) {
109 | case AUTO_PARSE:
110 | autoReceiveData();
111 |
112 | break;
113 | case MANUALLY_PARSE:
114 | boolean sendResult = Socketer.getInstance(MainActivity.this).sendStrData(reDataStr);//request
115 | if (!sendResult) {
116 | Toast.makeText(MainActivity.this, "send fail", Toast.LENGTH_SHORT).show();
117 | }
118 |
119 | break;
120 |
121 | default:
122 |
123 | break;
124 | }
125 | }
126 | });
127 | }
128 |
129 |
130 | private void manuallyParseListener() {
131 | Socketer.getInstance(MainActivity.this).setOnReceiveListener(new OnReceiveListener() {
132 | @Override
133 | public void onConnected(Socketer socketer) {
134 | Log.i(TAG, "服务器连接成功");
135 | }
136 |
137 | @Override
138 | public void onDisconnected(Socketer socketer) {
139 | Log.e(TAG, "服务器断开连接");
140 | }
141 |
142 | @Override
143 | public void onResponse(final String data) {
144 | runOnUiThread(new Runnable() {
145 | @Override
146 | public void run() {
147 | //response data
148 | tvResponse.setTextColor(getResources().getColor(R.color.blue));
149 | tvResponse.setText(data);
150 | }
151 | });
152 | }
153 | });
154 | }
155 |
156 | private void autoReceiveData() {
157 | //Socketer.getInstance(MainActivity.this).reConnectSever("192.168.2.171", 20083);
158 | Socketer.getInstance(MainActivity.this).sendStrData(reDataStr, "\"seq\":1000", new ResponseListener() {
159 | @Override
160 | public void onSuccess(final String data) {
161 | Log.i("Test server data", "callback data:" + data);
162 | runOnUiThread(new Runnable() {
163 | @Override
164 | public void run() {
165 | tvResponse.setTextColor(getResources().getColor(R.color.red));
166 | tvResponse.setText(data);
167 | }
168 | });
169 | }
170 |
171 | @Override
172 | public void onFail(final int failCode) {
173 | Log.e("Test server data", "callback error:" + failCode);
174 | runOnUiThread(new Runnable() {
175 | @Override
176 | public void run() {
177 | Toast.makeText(MainActivity.this, "返回错误码:" + failCode, Toast.LENGTH_SHORT).show();
178 | }
179 | });
180 | }
181 | });
182 | }
183 |
184 |
185 | }
186 |
--------------------------------------------------------------------------------
/app/src/main/java/com/virtue/socketdemo/bean/TestBean.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketdemo.bean;
2 |
3 | import java.io.Serializable;
4 |
5 | public class TestBean implements Serializable{
6 |
7 |
8 | public String protver;
9 | public int pkgtype;
10 | public int command;
11 | public int seq;
12 | public int terminaltype = 0;
13 | public String terminal = "";
14 | public int result = 0;
15 | public int bodylen = 200;
16 | public Inform body=new Inform() ;
17 |
18 | public class Inform implements Serializable {
19 | public String Phone ;
20 | public int cmd;
21 | public String getPhone() {
22 | return Phone;
23 | }
24 | public void setPhone(String phone) {
25 | Phone = phone;
26 | }
27 | public int getCmd() {
28 | return cmd;
29 | }
30 | public void setCmd(int cmd) {
31 | this.cmd = cmd;
32 | }
33 |
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/virtue/socketdemo/service/MySocketService.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketdemo.service;
2 |
3 | import android.app.Service;
4 | import android.content.BroadcastReceiver;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.IntentFilter;
8 | import android.os.IBinder;
9 | import android.support.annotation.Nullable;
10 | import android.util.Log;
11 |
12 | import com.virtue.socketlibrary.manager.Socketer;
13 | import com.virtue.socketlibrary.type.BroadCastType;
14 | import com.virtue.socketlibrary.type.ReceiveType;
15 |
16 | /**
17 | * Created by virtue on 2017/2/16.
18 | */
19 |
20 | public class MySocketService extends Service {
21 |
22 | private static final String TAG = "MySocketService";
23 | private MessageReceiver dataReceiver;
24 |
25 | @Nullable
26 | @Override
27 | public IBinder onBind(Intent intent) {
28 | return null;
29 | }
30 |
31 | @Override
32 | public void onCreate() {
33 | super.onCreate();
34 | //Demo in the LAN network, if you want to demo you need to modify your own server!
35 | Socketer.getInstance(getApplicationContext()).bindServerConnect("192.168.2.171", 20083)
36 | .setTimeout(10).setEncode("UTF_8")
37 | .setReceiveType(ReceiveType.SEPARATION_SIGN)
38 | .setEndCharSequence("\r\n") //服务器分割消息符
39 | .setMsgLength(1500).start();
40 | IntentFilter intentFilter = new IntentFilter();
41 | intentFilter.addAction(BroadCastType.SERVER_NOTICE);
42 | dataReceiver = new MessageReceiver();
43 | registerReceiver(dataReceiver, intentFilter);
44 | }
45 |
46 | class MessageReceiver extends BroadcastReceiver {
47 |
48 | @Override
49 | public void onReceive(Context context, Intent intent) {
50 | if (intent.getAction().equals(BroadCastType.SERVER_NOTICE)) {
51 | String dataStr = intent.getStringExtra(BroadCastType.SERVER_NOTICE_DATA);
52 | Log.i(TAG, "Data given to me by the server:" + dataStr);
53 | }
54 | }
55 | }
56 |
57 | @Override
58 | public void onDestroy() {
59 | super.onDestroy();
60 | if (dataReceiver != null) {
61 | unregisterReceiver(dataReceiver);
62 | Socketer.getInstance(getApplicationContext()).closeConnect();
63 | Socketer.getInstance(getApplicationContext()).closeSocketer();
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/virtue/socketdemo/utils/RequestUtil.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketdemo.utils;
2 |
3 | import java.util.regex.Matcher;
4 | import java.util.regex.Pattern;
5 | import java.util.regex.PatternSyntaxException;
6 |
7 | import android.content.Context;
8 | import android.net.ConnectivityManager;
9 | import android.net.NetworkInfo;
10 | import android.telephony.TelephonyManager;
11 |
12 | public class RequestUtil {
13 | private static int requestID = 100;
14 |
15 | /**
16 | * 获取手机IMEI
17 | *
18 | * @param context
19 | * @return
20 | */
21 | public static String getPhoneMini(Context context) {
22 | String imei = "";
23 | TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
24 | imei = telephonyManager.getDeviceId();// 手机IMEI
25 | if (imei == null || imei.length() < 1) {
26 | imei = "";
27 | }
28 | return imei;
29 | }
30 |
31 | /**
32 | * 检查该字符串是否只包含字母和数字
33 | * @param str
34 | * @return
35 | * @throws PatternSyntaxException
36 | */
37 | public static boolean StringFilter(String str) throws PatternSyntaxException {
38 | // 只允许字母和数字
39 | String regEx = "[a-zA-Z0-9]{6,16}";
40 | Pattern p = Pattern.compile(regEx);
41 | Matcher m = p.matcher(str);
42 | return m.matches();
43 | }
44 |
45 | /**
46 | * 检查当前网络是否可用
47 | *
48 | * @param context
49 | * @return
50 | */
51 | public static boolean isNetworkAvailable(Context context)
52 | {
53 | ConnectivityManager connectivityManager = (ConnectivityManager) context
54 | .getSystemService(Context.CONNECTIVITY_SERVICE);
55 |
56 | if (connectivityManager == null)
57 | {
58 | return false;
59 | }
60 | else
61 | {
62 | // 获取NetworkInfo对象
63 | NetworkInfo[] networkInfo = connectivityManager.getAllNetworkInfo();
64 | if (networkInfo != null && networkInfo.length > 0)
65 | {
66 | for (int i = 0; i < networkInfo.length; i++)
67 | {
68 | // 判断当前网络状态是否为连接状态
69 | if (networkInfo[i].getState() == NetworkInfo.State.CONNECTED)
70 | {
71 | return true;
72 | }
73 | }
74 | }
75 | }
76 | // 网络不可以用
77 | return false;
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
21 |
22 |
27 |
28 |
33 |
34 |
42 |
43 |
44 |
45 |
51 |
52 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zvirtuey/AndroidSocket/9cadeb1e1b9de5831407da809083bd192a924fb3/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zvirtuey/AndroidSocket/9cadeb1e1b9de5831407da809083bd192a924fb3/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zvirtuey/AndroidSocket/9cadeb1e1b9de5831407da809083bd192a924fb3/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zvirtuey/AndroidSocket/9cadeb1e1b9de5831407da809083bd192a924fb3/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zvirtuey/AndroidSocket/9cadeb1e1b9de5831407da809083bd192a924fb3/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #88ff0000
7 | #e30d00ff
8 | #ec29b10b
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AndroidSocket
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/virtue/socketdemo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketdemo;
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 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.2'
9 | classpath 'com.novoda:bintray-release:0.3.4'
10 | // classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
11 | // classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | jcenter()
20 | }
21 | tasks.withType(Javadoc) {
22 | options.addStringOption('Xdoclint:none', '-quiet')
23 | options.addStringOption('encoding', 'UTF-8')
24 | }
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/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 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zvirtuey/AndroidSocket/9cadeb1e1b9de5831407da809083bd192a924fb3/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':socketlibrary'
2 |
--------------------------------------------------------------------------------
/socketlibrary/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/socketlibrary/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | //apply plugin: 'com.github.dcendents.android-maven'
3 | //apply plugin: 'com.jfrog.bintray'
4 | apply plugin: 'maven'
5 | apply plugin: 'com.novoda.bintray-release'
6 |
7 | version = "1.0.7" //版本号,下次更新是只需要更改版本号即可
8 |
9 | android {
10 | compileSdkVersion 24
11 | buildToolsVersion "25.0.2"
12 |
13 | defaultConfig {
14 | minSdkVersion 9
15 | targetSdkVersion 28
16 | versionCode 1
17 | versionName "1.0.7"
18 |
19 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
20 |
21 | }
22 | buildTypes {
23 | release {
24 | minifyEnabled false
25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
26 | }
27 | }
28 | lintOptions {
29 | checkReleaseBuilds false
30 | abortOnError false
31 | }
32 | }
33 |
34 | dependencies {
35 | compile fileTree(include: ['*.jar'], dir: 'libs')
36 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
37 | exclude group: 'com.android.support', module: 'support-annotations'
38 | })
39 | //compile 'com.android.support:appcompat-v7:24.2.1'
40 | testCompile 'junit:junit:4.12'
41 | }
42 |
43 | //def siteUrl = 'https://github.com/Zvirtuey/AndroidSocket' // 修改为你的项目的主页
44 | //def gitUrl = 'https://github.com/Zvirtuey/AndroidSocket.git' // 修改为你的Git仓库的url
45 |
46 | //
47 | //group = "com.virtue.androidsocket" // Maven Group ID for the artifact,一般填你唯一的包名
48 | // 配置maven库,生成POM.xml文件
49 | //install {
50 | // repositories.mavenInstaller {
51 | // // This generates POM.xml with proper parameters
52 | // pom {
53 | // project {
54 | // packaging 'aar'
55 | // // Add your description here
56 | // name 'A simple Android socket communication, you are gonna love it' //项目描述
57 | // url siteUrl
58 | // // Set your license
59 | // licenses {
60 | // license {
61 | // name 'The Apache Software License, Version 2.0'
62 | // url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
63 | // }
64 | // }
65 | // developers {
66 | // developer {
67 | // id 'virtue' //填写的一些基本信息
68 | // name 'virtue'
69 | // email 'zvirtuey@outlook.com'
70 | // }
71 | // }
72 | // scm {
73 | // connection gitUrl
74 | // developerConnection gitUrl
75 | // url siteUrl
76 | // }
77 | // }
78 | // }
79 | // }
80 | //}
81 | //生成源文件
82 | //task sourcesJar(type: Jar) {
83 | // from android.sourceSets.main.java.srcDirs
84 | // classifier = 'sources'
85 | //}
86 | //生成文档
87 | task javadoc(type: Javadoc) {
88 | // source = android.sourceSets.main.java.srcDirs
89 | // classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
90 | options.encoding "UTF-8"
91 | options.charSet 'UTF-8'
92 | }
93 | //文档打包成jar
94 | //task javadocJar(type: Jar, dependsOn: javadoc) {
95 | // classifier = 'javadoc'
96 | // from javadoc.destinationDir
97 | //}
98 | //上传到jcenter所需要的源码文件
99 | //artifacts {
100 | // archives javadocJar
101 | // archives sourcesJar
102 | //}
103 | //上传到jcenter
104 | //Properties properties = new Properties()
105 | //properties.load(project.rootProject.file('local.properties').newDataInputStream())
106 |
107 | //bintray {
108 | // user = properties.getProperty("bintray.user") //读取 local.properties 文件里面的 bintray.user
109 | // key = properties.getProperty("bintray.apikey") //读取 local.properties 文件里面的 bintray.apikey
110 | // configurations = ['archives']
111 | // pkg {
112 | // repo = "maven"
113 | // name = "AndroidSocket" //发布到JCenter上的项目名字
114 | // websiteUrl = siteUrl
115 | // vcsUrl = gitUrl
116 | // licenses = ["Apache-2.0"]
117 | // publish = true
118 | // }
119 | //}
120 |
121 | publish {
122 | userOrg = 'virtue'
123 | groupId = 'com.virtue.androidsocket'
124 | artifactId = 'AndroidSocket'
125 | version = '1.0.7'
126 | description = 'A simple Android socket communication, you are gonna love it'
127 | website = "https://github.com/Zvirtuey/AndroidSocket"
128 | }
129 |
130 | //上传指令
131 | //gradlew clean build bintrayUpload -PbintrayUser=xxxx -PbintrayKey=xxxxxxxxxx -PdryRun=false
--------------------------------------------------------------------------------
/socketlibrary/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:\Users\virtue\Android\Android_Studio_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 |
--------------------------------------------------------------------------------
/socketlibrary/src/androidTest/java/com/virtue/socketlibrary/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketlibrary;
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.virtue.socketlibrary.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/socketlibrary/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/socketlibrary/src/main/java/com/virtue/socketlibrary/manager/Socketer.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketlibrary.manager;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.os.Handler;
6 | import android.os.Looper;
7 | import android.os.Message;
8 | import android.util.Log;
9 |
10 | import com.virtue.socketlibrary.type.ParseMode;
11 | import com.virtue.socketlibrary.type.ReceiveType;
12 | import com.virtue.socketlibrary.utils.OnReceiveListener;
13 | import com.virtue.socketlibrary.utils.ResponseListener;
14 | import com.virtue.socketlibrary.utils.SendBroadCastUtil;
15 | import com.virtue.socketlibrary.utils.SocketCode;
16 |
17 | import java.io.BufferedOutputStream;
18 | import java.io.DataInputStream;
19 | import java.io.IOException;
20 | import java.net.InetSocketAddress;
21 | import java.net.Socket;
22 | import java.net.SocketAddress;
23 | import java.util.ArrayList;
24 | import java.util.Collections;
25 | import java.util.Iterator;
26 | import java.util.List;
27 | import java.util.Map;
28 | import java.util.concurrent.ConcurrentHashMap;
29 | import java.util.concurrent.Executors;
30 | import java.util.concurrent.ScheduledExecutorService;
31 | import java.util.concurrent.TimeUnit;
32 |
33 | import static com.virtue.socketlibrary.type.ReceiveType.SEPARATION_SIGN;
34 |
35 | /**
36 | * Created by virtue on 2017/2/15.
37 | *
38 | * https://github.com/Zvirtuey/AndroidSocket
39 | */
40 |
41 | public class Socketer extends Thread {
42 |
43 | private static Context mContext;
44 | public Socket socket;
45 | //private BufferedWriter outputStream;
46 | private BufferedOutputStream outputStream;
47 | private DataInputStream inputStream;
48 | private static final String TAG = "Socketer";
49 | private String ip = "192.168.1.108"; //服务器地址(server address)
50 | private int port = 80; //服务器端口(server port)
51 | private int timeout = 15; //请求超时时长 单位秒(request time-out time unit sec)
52 | private int sendMaxByteLength = 1500; //发送字节数限制 单位字节(send byte limit unit byte)
53 | private boolean isRunning = true; //是否接受服务器数据(whether to accept server data)
54 | public boolean isConnected = false; //是否连接服务器(whether to connect to the server)
55 | private String encode = "UTF-8"; //编码(encode)
56 | private String endCharSequence = "\r\n"; //分割结束标识符(split end identifier)
57 | private String endData = ""; //尾部剩余数据(tail remaining data)
58 | private int msgLength = 2048; //固定长度分割(fixed-length segmentation)
59 | private ReceiveType receiveType = SEPARATION_SIGN; //接收方式(how to receive)
60 | private ParseMode parseMode = ParseMode.AUTO_PARSE; //解析方式(how to resolve)
61 | private SendMsgThread sendMsgThread;
62 | private ReceiveMsgThread receiveMsgThread;
63 | private ConcurrentHashMap mListenerMap;
64 | private ConcurrentHashMap mTimeOutMap;
65 | private List reqIdList;
66 | private OnReceiveListener mReceiveListener;
67 |
68 | private Socketer() {
69 | sendMsgThread = new SendMsgThread();
70 | receiveMsgThread = new ReceiveMsgThread();
71 | mListenerMap = new ConcurrentHashMap();
72 | mTimeOutMap = new ConcurrentHashMap();
73 | reqIdList = Collections.synchronizedList(new ArrayList());
74 | }
75 |
76 | public static final Socketer getInstance(Context context) {
77 | mContext = context.getApplicationContext();
78 | return SingleHolder.INSTANCE;
79 | }
80 |
81 | private static class SingleHolder {
82 | private static final Socketer INSTANCE = new Socketer(); // 创建实例的地方
83 | }
84 |
85 | public Socketer bindServerConnect(String address, int port) {
86 | this.ip = address;
87 | this.port = port;
88 | return this;
89 | }
90 |
91 | public void onStart() {
92 | this.start();
93 | }
94 |
95 | /**
96 | * 获取超时时间
97 | * Get timeouts
98 | *
99 | * @return
100 | */
101 | public int getTimeout() {
102 | return timeout;
103 | }
104 |
105 | /**
106 | * 设置超时时间
107 | * Set a timeout
108 | *
109 | * @param timeout
110 | * @return
111 | */
112 | public Socketer setTimeout(int timeout) {
113 | this.timeout = timeout;
114 | return this;
115 | }
116 |
117 | /**
118 | * 获取发送最大字节数
119 | * Get the maximum number of bytes to send
120 | *
121 | * @return
122 | */
123 | public int getSendMaxByteLength() {
124 | return sendMaxByteLength;
125 | }
126 |
127 | /**
128 | * 设置发送最大字节数
129 | * Set the maximum number of bytes to send
130 | *
131 | * @param sendMaxByteLength
132 | * @return
133 | */
134 | public Socketer setSendMaxByteLength(int sendMaxByteLength) {
135 | this.sendMaxByteLength = sendMaxByteLength;
136 | return this;
137 | }
138 |
139 | public String getEncode() {
140 | return encode;
141 | }
142 |
143 | /**
144 | * 设置编码
145 | * Set up the code
146 | *
147 | * @param encode
148 | * @return
149 | */
150 | public Socketer setEncode(String encode) {
151 | this.encode = encode;
152 | return this;
153 | }
154 |
155 | /**
156 | * 获取接收形式
157 | * Get the form of reception
158 | *
159 | * @return
160 | */
161 | public ReceiveType getReceiveType() {
162 | return receiveType;
163 | }
164 |
165 | /**
166 | * 设置接收形式
167 | * Set up the form of reception
168 | *
169 | * @param receiveType
170 | * @return
171 | */
172 | public Socketer setReceiveType(ReceiveType receiveType) {
173 | this.receiveType = receiveType;
174 | return this;
175 | }
176 |
177 | /**
178 | * 获取接收的固定长度值
179 | * Get a fixed-length value received
180 | *
181 | * @return
182 | */
183 | public int getMsgLength() {
184 | return msgLength;
185 | }
186 |
187 | /**
188 | * 设置接收固定长度值
189 | * Set a receive fixed length value
190 | *
191 | * @param msgLength
192 | * @return
193 | */
194 | public Socketer setMsgLength(int msgLength) {
195 | this.msgLength = msgLength;
196 | return this;
197 | }
198 |
199 | /**
200 | * 获取接收分割符
201 | * Get the receive split
202 | *
203 | * @return
204 | */
205 | public String getEndCharSequence() {
206 | return endCharSequence;
207 | }
208 |
209 | /**
210 | * 设置接收分隔符
211 | * Set the receive separator
212 | *
213 | * @param endCharSequence
214 | * @return
215 | */
216 | public Socketer setEndCharSequence(String endCharSequence) {
217 | this.endCharSequence = endCharSequence;
218 | return this;
219 | }
220 |
221 | /**
222 | * 设置响应的解析方式(默认是自动解析)
223 | * Set how the response is resolved (default is automatic resolution)
224 | *
225 | * @param mMode 解析方式枚举对象(ParseMode)
226 | * @return
227 | */
228 | public Socketer setParseMode(ParseMode mMode) {
229 | this.parseMode = mMode;
230 | return this;
231 | }
232 |
233 |
234 | /**
235 | * 获取响应时的解析方式(默认是自动解析)
236 | * How to get the resolution of the response (default is automatic resolution)
237 | *
238 | * @return
239 | */
240 | public ParseMode getParseMode() {
241 | return parseMode;
242 | }
243 |
244 | @Override
245 | public void run() {
246 | //开启超时任务
247 | scheduledExecutorService.scheduleWithFixedDelay(runnable, timeout, 1, TimeUnit.SECONDS);
248 | while (isRunning) {
249 | while (socket == null || !socket.isConnected() || isClosedServer(socket)) {
250 | try {
251 | connectSocket();
252 | Log.i(TAG, "Connecting the server");
253 | if (mReceiveListener != null) {
254 | mReceiveListener.onConnected(this);
255 | }
256 | } catch (IOException e) {
257 | e.printStackTrace();
258 | Log.e(TAG, "Connection server failed, please detect the network and server");
259 | if (isConnected == true) {
260 | isConnected = false;
261 | if (mReceiveListener != null) {
262 | mReceiveListener.onDisconnected(this);
263 | }
264 | SendBroadCastUtil.sendNetworkStateBroadcast(mContext, isConnected);
265 | }
266 | closeConnect();
267 | try {
268 | sleep(3000);
269 | } catch (InterruptedException e1) {
270 | e1.printStackTrace();
271 | }
272 | }
273 | }
274 | try {
275 | if (socket.isConnected() && inputStream != null) {
276 | if (isConnected == false) {
277 | isConnected = true;
278 | if (mReceiveListener != null) {
279 | mReceiveListener.onConnected(this);
280 | }
281 | SendBroadCastUtil.sendNetworkStateBroadcast(mContext, isConnected);
282 | }
283 | Log.i(TAG, "Connection server waiting to accept message");
284 | try {
285 | int len = 0;
286 | byte[] temp;
287 | if (msgLength > 0) {
288 | temp = new byte[msgLength];
289 | } else {
290 | temp = new byte[2048];
291 | }
292 | while ((len = inputStream.read(temp == null ? temp = new byte[2048] : temp)) != -1) {
293 |
294 | switch (receiveType) {
295 | case SEPARATION_SIGN: // 按包尾字符分割信息
296 | String tempData = new String(temp, 0, len);
297 | StringBuilder builder = new StringBuilder();
298 | builder.append(endData);
299 | builder.append(tempData);
300 | String totalStr = builder.toString();
301 | while (totalStr.contains(endCharSequence)) {
302 | String[] splitArray = totalStr.split(endCharSequence, 2);
303 | String mData = splitArray[0];
304 | endData = splitArray[1];
305 | totalStr = endData;
306 | executeReceiveTask(mData);
307 | }
308 |
309 | break;
310 |
311 | case FIXED_LENGTH: // 按固定长度分割信息
312 | if (msgLength > 0) {
313 | String allData = new String(temp, 0, len);
314 | executeReceiveTask(allData);
315 | } else {
316 | Log.e(TAG, "Set the number of bytes to receive a fixed size");
317 | }
318 |
319 | break;
320 |
321 | default:
322 | break;
323 | }
324 | }
325 | } catch (Exception e) {
326 | e.printStackTrace();
327 | Log.i(TAG, "No data to receive");
328 | }
329 | } else {
330 | inputStream = new DataInputStream(socket.getInputStream());
331 | Log.i(TAG, "Service not connected, reconnected...");
332 | }
333 | } catch (IOException e) {
334 | Log.e(TAG, "Server connection failed!");
335 | e.printStackTrace();
336 | if (socket != null) {
337 | try {
338 | socket.close();
339 | } catch (IOException e1) {
340 | e1.printStackTrace();
341 | }
342 | socket = null;
343 | }
344 | isConnected = false;
345 | if (mReceiveListener != null) {
346 | mReceiveListener.onDisconnected(this);
347 | }
348 | }
349 | }
350 | }
351 |
352 | /**
353 | * 请求服务器byte[]数据
354 | * Request server byte[] data
355 | *
356 | * @param bytes 请求byte数据
357 | * @param confirmId 服务器返回的唯一标识
358 | * @param responseListener 监听器
359 | */
360 | public synchronized void sendByteData(byte[] bytes, String confirmId, ResponseListener responseListener) {
361 | if (responseListener == null) {
362 | throw new IllegalArgumentException("responseListener must not be null");
363 | }
364 | if (isConnected) {
365 | boolean sendCode = executeSendTask(bytes, confirmId, responseListener);
366 | if (!sendCode) {
367 | responseListener.onFail(SocketCode.SEND_FAIL);
368 | }
369 | } else {
370 | responseListener.onFail(SocketCode.DISCONNECT);
371 | }
372 | }
373 |
374 | /**
375 | * 请求服务器String数据
376 | * Request server String data
377 | *
378 | * @param requestData 请求数据 (request data)
379 | * @param confirmId 服务器返回的唯一标识 (unique identity returned)
380 | * @param responseListener 监听器 (Listener)
381 | */
382 | public void sendStrData(String requestData, String confirmId, ResponseListener responseListener) {
383 | if (responseListener == null) {
384 | throw new IllegalArgumentException("responseListener must not be null");
385 | }
386 | if (isConnected) {
387 | boolean sendCode = executeSendTask(requestData, confirmId, responseListener);
388 | if (!sendCode) {
389 | responseListener.onFail(SocketCode.SEND_FAIL);
390 | }
391 | } else {
392 | responseListener.onFail(SocketCode.DISCONNECT);
393 | }
394 | }
395 |
396 | /**
397 | * 请求服务器String数据
398 | * Request server String data
399 | *
400 | * @param requestData 请求数据 (request data)
401 | * @return
402 | */
403 | public boolean sendStrData(String requestData) {
404 | boolean sendResult = false;
405 | if (isConnected) {
406 | sendResult = executeSendTask(requestData, null, null);
407 | }
408 | return sendResult;
409 | }
410 |
411 | private void connectSocket() throws IOException {
412 | endData = "";
413 | socket = new Socket();
414 | SocketAddress socketAddress = new InetSocketAddress(ip, port);
415 | socket.connect(socketAddress, 5 * 1000);
416 | socket.setTcpNoDelay(true); // 关闭 Nagle 算法
417 | socket.setReceiveBufferSize(1024 * 10000);
418 | outputStream = new BufferedOutputStream(socket.getOutputStream());
419 | //outputStream = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), encode));
420 | inputStream = new DataInputStream(socket.getInputStream());
421 | isRunning = true;
422 | }
423 |
424 | /**
425 | * 重新连接服务器,可以换服务器地址、端口
426 | * 如果重新连接的服务器配置信息不一样请先设置各个配置(如编码、解析方式、超时时间等),然后再调用此方法
427 | * Reconnect the server, you can change the server address and port, If the reconnected server
428 | * configuration information is different, set up individual configurations (e.g. encoding, resolution, timeout, etc.)
429 | * before calling this method.
430 | *
431 | * @param ip
432 | * @param port
433 | */
434 | public void reConnectSever(String ip, int port) {
435 | boolean isAlive = isAlive();
436 | if (isAlive) {
437 | Socketer.getInstance(mContext).closeConnect();
438 | Socketer.getInstance(mContext).closeSocketer();
439 | } else {
440 | bindServerConnect(ip, port).start();
441 | }
442 | Socketer.getInstance(mContext).bindServerConnect(ip, port);
443 |
444 | }
445 |
446 | /**
447 | * 关闭连接
448 | * close socket
449 | */
450 | public void closeConnect() {
451 | try {
452 | if (socket != null) {
453 | if (inputStream != null) {
454 | inputStream.close();
455 | }
456 | if (outputStream != null) {
457 | outputStream.close();
458 | }
459 | }
460 | } catch (Exception e) {
461 | e.printStackTrace(); // 关闭连接失败 close fail
462 | } finally {
463 | try {
464 | if (socket != null) {
465 | socket.close();
466 | socket = null;
467 | }
468 | } catch (IOException e) {
469 | e.printStackTrace();
470 | }
471 | }
472 | }
473 |
474 | public void closeSocketer() {
475 | reqIdList.clear();
476 | mTimeOutMap.clear();
477 | mListenerMap.clear();
478 | ip = "";
479 | }
480 |
481 | public Boolean isClosedServer(Socket socket) {
482 | try {
483 | socket.sendUrgentData(0xFF);// 发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信
484 | return false;
485 | } catch (Exception e) {
486 | return true;
487 | }
488 | }
489 |
490 | public synchronized boolean executeSendTask(byte[] data, String requestId, ResponseListener mListener) {
491 | if (sendMsgThread == null || !sendMsgThread.isAlive()) {
492 | sendMsgThread = new SendMsgThread();
493 | synchronized (sendMsgThread) {
494 | sendMsgThread.start();
495 | try {
496 | sendMsgThread.wait();
497 | } catch (Exception e) {
498 | e.printStackTrace();
499 | }
500 | }
501 | }
502 | if (sendMsgThread.mLooper == null || sendMsgThread.mHandler == null) {
503 | Log.e(TAG, "workerThread mLooper mHandler ERROR!");
504 | return false;
505 | }
506 | Message msg = Message.obtain();
507 | Bundle bundle = new Bundle();
508 | bundle.putByteArray("byte", data);
509 | bundle.putString("msgId", requestId);
510 | msg.setData(bundle);
511 | msg.obj = mListener;
512 | return sendMsgThread.mHandler.sendMessage(msg);
513 | }
514 |
515 | public synchronized boolean executeSendTask(String data, String requestId, ResponseListener mListener) {
516 | if (sendMsgThread == null || !sendMsgThread.isAlive()) {
517 | sendMsgThread = new SendMsgThread();
518 | synchronized (sendMsgThread) {
519 | sendMsgThread.start();
520 | try {
521 | sendMsgThread.wait();
522 | } catch (Exception e) {
523 | e.printStackTrace();
524 | }
525 | }
526 | }
527 | if (sendMsgThread.mLooper == null || sendMsgThread.mHandler == null) {
528 | Log.e(TAG, "workerThread mLooper mHandler ERROR!");
529 | return false;
530 | }
531 | Message msg = Message.obtain();
532 | Bundle bundle = new Bundle();
533 | bundle.putString("content", data);
534 | bundle.putString("msgId", requestId);
535 | msg.setData(bundle);
536 | msg.obj = mListener;
537 | return sendMsgThread.mHandler.sendMessage(msg);
538 | }
539 |
540 | public synchronized boolean executeReceiveTask(String data) {
541 | if (receiveMsgThread == null || !receiveMsgThread.isAlive()) {
542 | receiveMsgThread = new ReceiveMsgThread();
543 | synchronized (receiveMsgThread) {
544 | receiveMsgThread.start();
545 | try {
546 | receiveMsgThread.wait();
547 | } catch (Exception e) {
548 | e.printStackTrace();
549 | }
550 | }
551 | }
552 | if (receiveMsgThread.mReceiveLooper == null || receiveMsgThread.mHandler == null) {
553 | Log.e(TAG, "receiveMsgThread mLooper mHandler ERROR!");
554 | return false;
555 | }
556 | Message msg = Message.obtain();
557 | msg.obj = data;
558 | return receiveMsgThread.mHandler.sendMessage(msg);
559 | }
560 |
561 | public class SendMsgThread extends Thread {
562 | protected final String TAG = "SendMsgThread";
563 | private Handler mHandler;
564 | private Looper mLooper;
565 |
566 | public void run() {
567 | Looper.prepare();
568 | mLooper = Looper.myLooper();
569 | mHandler = new Handler(mLooper) {
570 | public void handleMessage(Message msg) {
571 | Bundle mArgs = msg.getData();
572 | byte[] mBytes = mArgs.getByteArray("byte");
573 | String mData = mArgs.getString("content");
574 | String mReqId = mArgs.getString("msgId");
575 | ResponseListener responseListener = (ResponseListener) msg.obj;
576 | if (mData != null && !mData.equals("") && mData.length() > 0) {
577 | mBytes = mData.getBytes();
578 | }
579 | if (socket == null || !socket.isConnected()) {
580 | try {
581 | connectSocket();
582 | } catch (IOException e) {
583 | e.printStackTrace();
584 | if (parseMode == ParseMode.AUTO_PARSE) {
585 | responseListener.onFail(SocketCode.DISCONNECT);
586 | }
587 | Log.e(TAG, "Failed to connect to the server, please detect the network -->" + e);
588 | return;
589 | }
590 | }
591 | if (outputStream == null) {
592 | try {
593 | outputStream = new BufferedOutputStream(socket.getOutputStream());
594 | //outputStream = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), encode));
595 | } catch (IOException e) {
596 | e.printStackTrace();
597 | if (parseMode == ParseMode.AUTO_PARSE) {
598 | responseListener.onFail(SocketCode.SEND_FAIL);
599 | }
600 | Log.e(TAG, "Failed to send a fetch stream -->" + e);
601 | return;
602 | }
603 | }
604 | Log.i(TAG, "The length of the requested data :" + mData.length() + "\nRequest data :" + mData);
605 | if (mBytes.length > sendMaxByteLength
606 | && parseMode == ParseMode.AUTO_PARSE) {
607 | responseListener.onFail(SocketCode.SEND_TO_LONG);
608 | return;
609 | }
610 |
611 | try {
612 | if (mReqId != null && !mReqId.equals("")
613 | && parseMode == ParseMode.AUTO_PARSE) {
614 | mListenerMap.put(mReqId, responseListener);
615 | reqIdList.add(mReqId);
616 | long sendTime = System.currentTimeMillis();
617 | mTimeOutMap.put(mReqId, sendTime);
618 | }
619 | outputStream.write(mBytes);
620 | outputStream.flush();
621 | Log.i(TAG, "message send successful");
622 | } catch (IOException e) {
623 | e.printStackTrace();
624 | if (parseMode == ParseMode.AUTO_PARSE) {
625 | responseListener.onFail(SocketCode.SEND_FAIL);
626 | }
627 | Log.e(TAG, "send failed -->" + e);
628 | try {
629 | socket.close();
630 | } catch (IOException e1) {
631 | e1.printStackTrace();
632 | Log.e(TAG, "close stream failed -->" + e1);
633 | }
634 | socket = null;
635 | return;
636 | }
637 | }
638 | };
639 | synchronized (this) {
640 | try {
641 | notify();
642 | } catch (Exception e) {
643 | e.printStackTrace();
644 | }
645 | }
646 | Looper.loop();
647 | }
648 | }
649 |
650 | public class ReceiveMsgThread extends Thread {
651 | protected final String TAG = "ReceiveMsgThread";
652 | private Handler mHandler;
653 | private Looper mReceiveLooper;
654 |
655 | public void run() {
656 | Looper.prepare();
657 | mReceiveLooper = Looper.myLooper();
658 | mHandler = new Handler(mReceiveLooper) {
659 | public void handleMessage(Message msg) {
660 | String mData = (String) msg.obj;
661 | Log.v(TAG, "reqIdList size: " + reqIdList.size() + "\nData returned by the server:" + "\n" + mData);
662 | switch (parseMode) {
663 | case AUTO_PARSE: //自动解析 Auto Parse
664 | autoParseData(mData);
665 |
666 | break;
667 | case MANUALLY_PARSE: //手动解析 Manually Parse
668 | if (mReceiveListener != null) {
669 | mReceiveListener.onResponse(mData);
670 | }
671 |
672 | break;
673 |
674 | default:
675 |
676 | break;
677 | }
678 | }
679 | };
680 | synchronized (this) {
681 | try {
682 | notify();
683 | } catch (Exception e) {
684 | e.printStackTrace();
685 | }
686 | }
687 | Looper.loop();
688 | }
689 |
690 | private void autoParseData(String mData) {
691 | if (reqIdList == null || reqIdList.size() <= 0) {
692 | SendBroadCastUtil.sendServerData(mContext, mData);
693 | return;
694 | }
695 | for (String mStr : reqIdList) {
696 | Log.v(TAG, mStr);
697 | if (mData.contains(mStr)) {
698 | if (mListenerMap.containsKey(mStr)) {
699 | ResponseListener responseListener = mListenerMap.get(mStr);
700 | responseListener.onSuccess(mData);
701 | mListenerMap.remove(mStr);
702 | reqIdList.remove(mStr);
703 | if (mTimeOutMap.containsKey(mStr)) {
704 | mTimeOutMap.remove(mStr);
705 | }
706 | }
707 | } else {
708 | SendBroadCastUtil.sendServerData(mContext, mData);
709 | }
710 | }
711 | }
712 | }
713 |
714 | public void setOnReceiveListener(OnReceiveListener receiveListener) {
715 | if (receiveListener == null) {
716 | throw new IllegalArgumentException("receiveListener must not be null");
717 | }
718 | mReceiveListener = receiveListener;
719 |
720 | }
721 |
722 | private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
723 | //超时处理(Time out)
724 | private Runnable runnable = new Runnable() {
725 | @Override
726 | public void run() {
727 | if (mTimeOutMap != null && mTimeOutMap.size() > 0) {
728 | long receiveTime = System.currentTimeMillis();
729 | Iterator> entries = mTimeOutMap.entrySet().iterator();
730 | while (entries.hasNext()) {
731 | Map.Entry entry = entries.next();
732 | String reStrId = entry.getKey();
733 | long sendTime = entry.getValue();
734 | if (receiveTime - sendTime > timeout * 1000) {
735 | if (mListenerMap.containsKey(reStrId)) {
736 | ResponseListener responseListener = mListenerMap.get(reStrId);
737 | responseListener.onFail(SocketCode.TIME_OUT);
738 | mListenerMap.remove(reStrId);
739 | mTimeOutMap.remove(reStrId);
740 | if (reqIdList.contains(reStrId)) {
741 | reqIdList.remove(reStrId);
742 | }
743 | }
744 | }
745 | System.out.println("Time out Key = " + entry.getKey() + ", Time outValue = " + entry.getValue());
746 | }
747 | }
748 | }
749 | };
750 |
751 |
752 | }
753 |
--------------------------------------------------------------------------------
/socketlibrary/src/main/java/com/virtue/socketlibrary/type/BroadCastType.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketlibrary.type;
2 |
3 | /**
4 | * Created by virtue on 2017/6/10.
5 | */
6 |
7 | public interface BroadCastType {
8 | String IS_CONNECTED="is_connected"; //网络连接携带参数标记
9 | String NETWORK_CONNECT_STATE="network_connect_state"; //发送网络连接的广播Action
10 | String SERVER_NOTICE_DATA ="server_data"; //服务器主推数据参数标记
11 | String SERVER_NOTICE="server_notice"; //发送服务器主推的广播Action
12 | String RESPONSE_RESULT_DATA ="response_result_data"; //请求响应的数据参数标记
13 | // String RESPONSE_RESULT_LISTENER ="response_result_listener"; //请求结果数据对应的监听器参数标记
14 | // String RESPONSE_RESULT="server_result"; //发送请求获得响应的广播Action
15 | }
16 |
--------------------------------------------------------------------------------
/socketlibrary/src/main/java/com/virtue/socketlibrary/type/ParseMode.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketlibrary.type;
2 |
3 | /**
4 | * Created by Virtue on 2017/10/23.
5 | */
6 |
7 | public enum ParseMode {
8 | AUTO_PARSE,//自动解析(Auto Parse)
9 | MANUALLY_PARSE //手动解析(Manually Parse)
10 | }
11 |
--------------------------------------------------------------------------------
/socketlibrary/src/main/java/com/virtue/socketlibrary/type/ReceiveType.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketlibrary.type;
2 |
3 | /**
4 | * Created by virtue on 2017/6/19.
5 | */
6 |
7 | public enum ReceiveType {
8 | SEPARATION_SIGN //分隔符(Separator)
9 | , FIXED_LENGTH //固定长度(Fixed length)
10 | }
11 |
--------------------------------------------------------------------------------
/socketlibrary/src/main/java/com/virtue/socketlibrary/utils/ChangeTypeUtil.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketlibrary.utils;
2 |
3 | public class ChangeTypeUtil {
4 |
5 | /**
6 | * 将int值转成网络字节
7 | *
8 | * @return 返回网络字节数组
9 | */
10 | public static byte[] intToByteArray(int a) {
11 | return new byte[]{(byte) ((a >> 24) & 0xFF), (byte) ((a >> 16) & 0xFF), (byte) ((a >> 8) & 0xFF),
12 | (byte) (a & 0xFF)};
13 | }
14 |
15 | /**
16 | * 将byte[]转成int
17 | *
18 | * @param b
19 | * @return
20 | */
21 | public static int byteArrayToInt(byte[] b) {
22 | // return b[3] & 0xFF | (b[2] & 0xFF) << 8 | (b[1] & 0xFF) << 16 | (b[0]
23 | // & 0xFF) << 24;
24 | return (b[0] & 0xFF) << 24 | (b[1] & 0xFF) << 16 | (b[2] & 0xFF) << 8 | b[3] & 0xFF;
25 |
26 | }
27 |
28 | // 将指定byte数组以16进制的形式打印到控制台
29 | public static void printHexString(byte[] b) {
30 | for (int i = 0; i < b.length; i++) {
31 | String hex = Integer.toHexString(b[i] & 0xFF);
32 | if (hex.length() == 1) {
33 | hex = '0' + hex;
34 | }
35 | String ret = "";
36 | System.out.println(hex.toUpperCase() + " ");
37 | }
38 |
39 | }
40 |
41 | // public static byte[] charArrayToByteArray(char[] cChar){
42 | // byte[] byteData=Encoding.Default.GetBytes(cChar);
43 | // return byteData;
44 | // }
45 | //
46 | // public static char[] byteArrayToCharArray(byte[] byteData){
47 | // char[] cChar=Encoding.ASCII.GetChars(byteData);
48 | // return cChar;
49 | // }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/socketlibrary/src/main/java/com/virtue/socketlibrary/utils/OnReceiveListener.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketlibrary.utils;
2 |
3 | import com.virtue.socketlibrary.manager.Socketer;
4 |
5 | /**
6 | * Created by Virtue on 2017/10/24.
7 | */
8 |
9 | public interface OnReceiveListener {
10 | //socket connection successful 连接成功
11 | void onConnected(Socketer socketer);
12 |
13 | //socket connection failed 连接失败
14 | void onDisconnected(Socketer socketer);
15 |
16 | //socket data response 数据响应
17 | void onResponse(String data);
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/socketlibrary/src/main/java/com/virtue/socketlibrary/utils/ResponseListener.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketlibrary.utils;
2 |
3 | /**
4 | * Created by virtue on 2017/6/10.
5 | */
6 |
7 | public interface ResponseListener {
8 |
9 | //response data
10 | void onSuccess(String data);
11 |
12 | //failed code
13 | void onFail(int failCode);
14 | }
15 |
--------------------------------------------------------------------------------
/socketlibrary/src/main/java/com/virtue/socketlibrary/utils/SendBroadCastUtil.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketlibrary.utils;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 |
6 | import com.virtue.socketlibrary.type.BroadCastType;
7 |
8 | public class SendBroadCastUtil {
9 |
10 | /**
11 | * 发送网络状态广播 (send network Network status)
12 | *
13 | * @param mContext
14 | * @param isConnected
15 | */
16 | public static void sendNetworkStateBroadcast(Context mContext, boolean isConnected) {
17 | Intent intent = new Intent();
18 | intent.putExtra(BroadCastType.IS_CONNECTED, isConnected);
19 | intent.setAction(BroadCastType.NETWORK_CONNECT_STATE);
20 | mContext.sendBroadcast(intent);
21 | }
22 |
23 | /**
24 | * 发送服务器主推通知信息 (send message from server)
25 | *
26 | * @param mContext
27 | * @param mData
28 | */
29 | public static void sendServerData(Context mContext, String mData) {
30 | Intent intent = new Intent();
31 | intent.putExtra(BroadCastType.SERVER_NOTICE_DATA, mData);
32 | intent.setAction(BroadCastType.SERVER_NOTICE);
33 | mContext.sendBroadcast(intent);
34 | }
35 |
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/socketlibrary/src/main/java/com/virtue/socketlibrary/utils/SocketCode.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketlibrary.utils;
2 |
3 | public interface SocketCode {
4 | int SUCCESS = 0; //发送成功(send succeed)
5 | int SEND_FAIL = 1; //发送失败 (send fail)
6 | int TIME_OUT = 2; //发送超时 (overtime)
7 | int SEND_TO_LONG = 3; //发送数据过长 (send so long)
8 | int DISCONNECT = -1; //连接断开 (disconnected)
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/socketlibrary/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SocketLibrary
3 |
4 |
--------------------------------------------------------------------------------
/socketlibrary/src/test/java/com/virtue/socketlibrary/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketlibrary;
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 | }
--------------------------------------------------------------------------------