diff --git a/AndroidTemplate/.gitignore b/AndroidTemplate/.gitignore new file mode 100644 index 0000000..39fb081 --- /dev/null +++ b/AndroidTemplate/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/AndroidTemplate/.idea/gradle.xml b/AndroidTemplate/.idea/gradle.xml new file mode 100644 index 0000000..f44e04a --- /dev/null +++ b/AndroidTemplate/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/AndroidTemplate/.idea/misc.xml b/AndroidTemplate/.idea/misc.xml new file mode 100644 index 0000000..ba7052b --- /dev/null +++ b/AndroidTemplate/.idea/misc.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/AndroidTemplate/.idea/modules.xml b/AndroidTemplate/.idea/modules.xml new file mode 100644 index 0000000..1d34556 --- /dev/null +++ b/AndroidTemplate/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/AndroidTemplate/.idea/runConfigurations.xml b/AndroidTemplate/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/AndroidTemplate/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/AndroidTemplate/app/.gitignore b/AndroidTemplate/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/AndroidTemplate/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/AndroidTemplate/app/build.gradle b/AndroidTemplate/app/build.gradle new file mode 100644 index 0000000..ac690c9 --- /dev/null +++ b/AndroidTemplate/app/build.gradle @@ -0,0 +1,31 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 26 + defaultConfig { + applicationId "com.example.UserSoftwareAndroidTemplate" + minSdkVersion 19 + targetSdkVersion 26 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + buildToolsVersion '27.0.0' +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'com.android.support:appcompat-v7:26.1.0' + implementation 'com.android.support.constraint:constraint-layout:1.0.2' + implementation 'com.android.support:design:26.1.0' + implementation 'com.android.support:support-v4:26.1.0' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.1' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' +} diff --git a/AndroidTemplate/app/proguard-rules.pro b/AndroidTemplate/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/AndroidTemplate/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/AndroidTemplate/app/src/androidTest/java/com/example/UserSoftwareAndroidTemplate/ExampleInstrumentedTest.java b/AndroidTemplate/app/src/androidTest/java/com/example/UserSoftwareAndroidTemplate/ExampleInstrumentedTest.java new file mode 100644 index 0000000..32ea99b --- /dev/null +++ b/AndroidTemplate/app/src/androidTest/java/com/example/UserSoftwareAndroidTemplate/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.example.UserSoftwareAndroidTemplate; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("com.example.UserSoftwareAndroidTemplate", appContext.getPackageName()); + } +} diff --git a/AndroidTemplate/app/src/main/AndroidManifest.xml b/AndroidTemplate/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..3f6dd97 --- /dev/null +++ b/AndroidTemplate/app/src/main/AndroidManifest.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/BasicFramework/SoftBasic.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/BasicFramework/SoftBasic.java new file mode 100644 index 0000000..190c047 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/BasicFramework/SoftBasic.java @@ -0,0 +1,13 @@ +package com.example.HslCommunication.BasicFramework; + +/** + * Created by hsl20 on 2017/11/4. + * 静态类,提供许多程序运行的方法 + */ + +public class SoftBasic { + + + + +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/BasicFramework/SystemVersion.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/BasicFramework/SystemVersion.java new file mode 100644 index 0000000..b1a2aed --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/BasicFramework/SystemVersion.java @@ -0,0 +1,156 @@ +package com.example.HslCommunication.BasicFramework; + +/** + * Created by hsl20 on 2017/11/4. + */ + +public class SystemVersion { + + /// + /// 根据格式化字符串的版本号初始化 + /// + /// 格式化的字符串,例如:1.0.0或1.0.0.0503 + public SystemVersion(String VersionString) + { + String[] temp = VersionString.split("\\."); + if (temp.length >= 3) + { + m_MainVersion = Integer.parseInt(temp[0]); + m_SecondaryVersion = Integer.parseInt(temp[1]); + m_EditVersion = Integer.parseInt(temp[2]); + + if (temp.length >= 4) + { + m_InnerVersion = Integer.parseInt(temp[3]); + } + } + } + /// + /// 根据指定的数字实例化一个对象 + /// + /// 主版本 + /// 次版本 + /// 修订版 + public SystemVersion(int main, int sec, int edit) + { + m_MainVersion = main; + m_SecondaryVersion = sec; + m_EditVersion = edit; + } + /// + /// 根据指定的数字实例化一个对象 + /// + /// 主版本 + /// 次版本 + /// 修订版 + /// 内部版本号 + public SystemVersion(int main, int sec, int edit, int inner) + { + m_MainVersion = main; + m_SecondaryVersion = sec; + m_EditVersion = edit; + m_InnerVersion = inner; + } + private int m_MainVersion = 2; + /// + /// 主版本 + /// + public int MainVersion() + { + return m_MainVersion; + } + private int m_SecondaryVersion = 0; + /// + /// 次版本 + /// + public int SecondaryVersion() { + return m_SecondaryVersion; + } + + private int m_EditVersion = 0; + /// + /// 修订版 + /// + public int EditVersion() { + return m_EditVersion; + } + private int m_InnerVersion = 0; + /// + /// 内部版本号,或者是版本号表示为年月份+内部版本的表示方式 + /// + public int InnerVersion() + { + return m_InnerVersion; + } + + /// + /// 根据格式化为支持返回的不同信息的版本号 + /// C返回1.0.0.0 + /// N返回1.0.0 + /// S返回1.0 + /// + /// 格式化信息 + /// + public String toString(String format) + { + if(format == "C") + { + return MainVersion()+"."+SecondaryVersion()+"."+EditVersion()+"."+InnerVersion(); + } + + if(format == "N") + { + return MainVersion()+"."+SecondaryVersion()+"."+EditVersion(); + } + + if(format == "S") + { + return MainVersion()+"."+SecondaryVersion(); + } + + return toString(); + } + + + + @Override + public String toString() { + if(InnerVersion() == 0) + { + return MainVersion()+"."+SecondaryVersion()+"."+EditVersion(); + } + else + { + return MainVersion()+"."+SecondaryVersion()+"."+EditVersion()+"."+InnerVersion(); + } + } + + + public boolean IsSameVersion(SystemVersion sv) + { + if(this.m_MainVersion!=sv.m_MainVersion) + { + return false; + } + + if(this.m_SecondaryVersion!=sv.m_SecondaryVersion) + { + return false; + } + + if(this.m_EditVersion!=sv.m_EditVersion) + { + return false; + } + + if(this.m_InnerVersion!=sv.m_InnerVersion) + { + return false; + } + + return true; + } + + + +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/HslCommunicationCode.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/HslCommunicationCode.java new file mode 100644 index 0000000..0c9d55b --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/HslCommunicationCode.java @@ -0,0 +1,100 @@ +package com.example.HslCommunication.Core.Net; + +/** + * Created by DATHLIN on 2017/11/1. + */ + +public class HslCommunicationCode { + + + /// + /// 规定所有的网络传输指令头都为32字节 + /// + public static final int HeadByteLength = 32; + + + /// + /// 用于心跳程序的暗号信息 + /// + public static final int Hsl_Protocol_Check_Secends = 1; + /// + /// 客户端退出消息 + /// + public static final int Hsl_Protocol_Client_Quit = 2; + /// + /// 因为客户端达到上限而拒绝登录 + /// + public static final int Hsl_Protocol_Client_Refuse_Login = 3; + /// + /// 允许客户端登录到服务器 + /// + public static final int Hsl_Protocol_Client_Allow_Login = 4; + + + + + /// + /// 说明发送的只是文本信息 + /// + public static final int Hsl_Protocol_User_String = 1001; + /// + /// 发送的数据就是普通的字节数组 + /// + public static final int Hsl_Protocol_User_Bytes = 1002; + /// + /// 发送的数据就是普通的图片数据 + /// + public static final int Hsl_Protocol_User_Bitmap = 1003; + /// + /// 发送的数据是一条异常的数据,字符串为异常消息 + /// + public static final int Hsl_Protocol_User_Exception = 1004; + + + + + /// + /// 请求文件下载的暗号 + /// + public static final int Hsl_Protocol_File_Download = 2001; + /// + /// 请求文件上传的暗号 + /// + public static final int Hsl_Protocol_File_Upload = 2002; + /// + /// 请求删除文件的暗号 + /// + public static final int Hsl_Protocol_File_Delete = 2003; + /// + /// 文件校验成功 + /// + public static final int Hsl_Protocol_File_Check_Right = 2004; + /// + /// 文件校验失败 + /// + public static final int Hsl_Protocol_File_Check_Error = 2005; + /// + /// 文件保存失败 + /// + public static final int Hsl_Protocol_File_Save_Error = 2006; + /// + /// 请求文件列表的暗号 + /// + public static final int Hsl_Protocol_File_Directory_Files = 2007; + /// + /// 请求子文件的列表暗号 + /// + public static final int Hsl_Protocol_File_Directories = 2008; + + + + + /// + /// 不压缩数据字节 + /// + public static final int Hsl_Protocol_NoZipped = 3001; + /// + /// 压缩数据字节 + /// + public static final int Hsl_Protocol_Zipped = 3002; +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/HslSecurity.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/HslSecurity.java new file mode 100644 index 0000000..6bcb592 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/HslSecurity.java @@ -0,0 +1,35 @@ +package com.example.HslCommunication.Core.Net; + +/** + * Created by DATHLIN on 2017/11/1. + */ + +public class HslSecurity { + + + /// + /// 加密方法,只对当前的程序集开放 + /// + /// 等待加密的数据 + /// 加密后的数据 + public static byte[] ByteEncrypt(byte[] enBytes) { + if (enBytes == null) return null; + byte[] result = new byte[enBytes.length]; + for (int i = 0; i < enBytes.length; i++) { + result[i] = (byte) (enBytes[i] ^ 0xB5); + } + return result; + } + + + /// + /// 解密方法,只对当前的程序集开放 + /// + /// 等待解密的数据 + /// 解密后的数据 + public static byte[] ByteDecrypt(byte[] deBytes) { + return ByteEncrypt(deBytes); + } + + +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/HslZipped.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/HslZipped.java new file mode 100644 index 0000000..6e46f33 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/HslZipped.java @@ -0,0 +1,64 @@ +package com.example.HslCommunication.Core.Net; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +/** + * Created by DATHLIN on 2017/11/1. + */ + +public class HslZipped { + + + /*** + * 压缩GZip + * + * @param data + * @return + */ + public static byte[] CompressBytes(byte[] data) { + byte[] b = null; + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + GZIPOutputStream gzip = new GZIPOutputStream(bos); + gzip.write(data); + gzip.finish(); + gzip.close(); + b = bos.toByteArray(); + bos.close(); + } catch (Exception ex) { + ex.printStackTrace(); + } + return b; + } + + /*** + * 解压GZip + * + * @param data + * @return + */ + public static byte[] Decompress(byte[] data) { + byte[] b = null; + try { + ByteArrayInputStream bis = new ByteArrayInputStream(data); + GZIPInputStream gzip = new GZIPInputStream(bis); + byte[] buf = new byte[1024]; + int num = -1; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + while ((num = gzip.read(buf, 0, buf.length)) != -1) { + baos.write(buf, 0, num); + } + b = baos.toByteArray(); + baos.flush(); + baos.close(); + gzip.close(); + bis.close(); + } catch (Exception ex) { + ex.printStackTrace(); + } + return b; + } +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/NetBase.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/NetBase.java new file mode 100644 index 0000000..178a153 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/NetBase.java @@ -0,0 +1,320 @@ +package com.example.HslCommunication.Core.Net; +import android.util.Log; + +import com.example.HslCommunication.Core.Types.HslTimeOut; +import com.example.HslCommunication.Core.Types.OperateResult; +import com.example.HslCommunication.Core.Utilities.boolWithBytes; +import com.example.HslCommunication.Core.Utilities.boolWithSocket; +import com.example.HslCommunication.Log.LogUtil; +import com.example.HslCommunication.Resources.StringResources; + + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.DataOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.util.UUID; + + +/** + * Created by DATHLIN on 2017/11/1. + * 该类提供基础的网络操作服务,读写字节流,读写文件流 + */ + + + +public abstract class NetBase { + + /// + /// 用于通信工作的核心对象 + /// + protected Socket WorkSocket = null; + /// + /// 分次接收的数据长度 + /// + public int SegmentationLength = 1024; + + /// + /// 检查超时的子线程 + /// + /// + public void ThreadPoolCheckConnect(Object obj) { + HslTimeOut timeout = (HslTimeOut) obj; + if (timeout != null) { + NetSupport.ThreadPoolCheckConnect(timeout, ConnectTimeout); + } + } + + + /// + /// 网络访问中的超时时间,单位:毫秒,默认值5000 + /// + public int ConnectTimeout = 5000; + + /// + /// 当前对象的身份令牌,用来在网络通信中双向认证的依据 + /// + public UUID KeyToken = UUID.randomUUID(); + + + /**************************************************************************** + * + * 1. 创建并连接套接字 + * 2. 接收指定长度的字节数据 + * 3. 发送字节数据到套接字 + * 4. 检查对方是否接收完成 + * 5. 检查头子节令牌是否通过 + * 6. 将文件流写入套接字 + * 7. 从套接字接收文件流 + * + ****************************************************************************/ + + + /// + /// 创建socket对象并尝试连接终结点,如果异常,则结束通信 + /// + /// 网络套接字 + /// 网络终结点 + /// 结果对象 + /// + /// + protected boolWithSocket CreateSocketAndConnect( + String ipAddress, + int port, + OperateResult result + ) { + boolWithSocket value = new boolWithSocket(); + try { + // create the socket object + value.Socket = new Socket(ipAddress, port); + value.Result = true; + return value; + } catch (Exception ex) { + result.Message = StringResources.ConnectedFailed; + LogUtil.LogE("CreateSocketAndConnect", StringResources.ConnectedFailed, ex); + CloseSocket(value.Socket); + return value; + } + } + + + /// + /// 仅仅接收一定长度的字节数据,如果异常,则结束通信 + /// + /// 套接字 + /// 字节数据 + /// 长度 + /// 结果对象 + /// 接收状态 + /// 是否根据百分比报告进度 + /// 是否回发进度 + /// 是否进行超时检查 + /// 假设发生异常,应该携带什么信息 + /// + protected boolWithBytes ReceiveBytesFromSocket( + Socket socket, + int length, + OperateResult result, + ProgressReport receiveStatus, + boolean reportByPercent, + boolean response, + boolean checkTimeOut, + String exceptionMessage + ) { + boolWithBytes value = new boolWithBytes(); + + try { + value.Content = NetSupport.ReadBytesFromSocket(socket, length, receiveStatus, reportByPercent, response); + } catch (Exception ex) { + CloseSocket(socket); + result.Message = CombineExceptionString(exceptionMessage, ex.getMessage()); + LogUtil.LogE("ReceiveBytesFromSocket", exceptionMessage, ex); + Log.e("接收数据异常", "ReceiveBytesFromSocket: ", ex); + return value; + } + value.Result = true; + return value; + } + + /// + /// 仅仅将数据发送到socket对象上去,如果异常,则结束通信 + /// + /// + /// + /// + /// + /// + protected boolean SendBytesToSocket( + Socket socket, + byte[] send, + OperateResult result, + String exceptionMessage + ) { + try { + DataOutputStream output = new DataOutputStream(socket.getOutputStream()); + output.write(send); + } catch (Exception ex) { + result.Message = CombineExceptionString(exceptionMessage, ex.getLocalizedMessage()); + LogUtil.LogE("SendBytesToSocket", exceptionMessage, ex); + CloseSocket(socket); + send = null; + return false; + } + return true; + } + + + /// + /// 确认对方是否已经接收完成数据,如果异常,则结束通信 + /// + /// + /// + /// + /// + /// + /// + protected boolean CheckRomoteReceived( + Socket socket, + long length, + ProgressReport report, + OperateResult result, + String exceptionMessage + ) { + try { + NetSupport.CheckSendBytesReceived(socket, length, report, true); + return true; + } catch (Exception ex) { + result.Message = CombineExceptionString(exceptionMessage, ex.getLocalizedMessage()); + LogUtil.LogE("CheckRomoteReceived", exceptionMessage, ex); + CloseSocket(socket); + return false; + } + } + + + /// + /// 检查令牌是否正确,如果不正确,结束网络通信 + /// + /// 套接字 + /// 头子令 + /// 令牌 + /// 结果对象 + /// + protected boolean CheckTokenPermission( + Socket socket, + byte[] head, + UUID token, + OperateResult result + ) { + if (NetSupport.CheckTokenEquel(head, KeyToken)) { + return true; + } else { + result.Message = StringResources.TokenCheckFailed; + LogUtil.LogE("CheckTokenPermission", StringResources.TokenCheckFailed + " Ip:" + socket.getInetAddress().toString()); + CloseSocket(socket); + return false; + } + } + + /// + /// 将文件数据发送至套接字,如果结果异常,则结束通讯 + /// + /// + /// + /// + /// + /// + /// + /// + protected boolean SendFileStreamToSocket( + Socket socket, + String filename, + long filelength, + OperateResult result, + ProgressReport report, + String exceptionMessage + ) { + try { + InputStream inputStream = new BufferedInputStream(new FileInputStream(filename)); + NetSupport.WriteSocketFromStream(socket, inputStream, filelength, report, true); + inputStream.close(); + return true; + } catch (Exception ex) { + CloseSocket(socket); + LogUtil.LogE("SendFileStreamToSocket", exceptionMessage, ex); + result.Message = CombineExceptionString(exceptionMessage, ex.getLocalizedMessage()); + return false; + } + } + + + /// + /// 从套接字中接收一个文件数据,如果结果异常,则结束通讯 + /// + /// + /// + /// + /// + /// + /// + /// + protected boolean ReceiveFileSteamFromSocket( + Socket socket, + String filename, + long receive, + ProgressReport report, + OperateResult result, + String exceptionMessage + ) { + try { + OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(filename)); + NetSupport.WriteStreamFromSocket(socket, outputStream, receive, report, true); + outputStream.close(); + return true; + } catch (Exception ex) { + result.Message = CombineExceptionString(exceptionMessage, ex.getLocalizedMessage()); + LogUtil.LogE("ReceiveFileSteamFromSocket", exceptionMessage, ex); + CloseSocket(socket); + return false; + } + } + + /// + /// 获取错误的用于显示的信息 + /// + /// + /// + /// + protected String CombineExceptionString(String message, String exception) { + return message + "\r\n原因:" + exception; + } + + + + protected void CloseSocket(Socket socket) { + if (socket != null) { + try { + socket.close(); + } catch (Exception ex2) { + LogUtil.LogE("CloseSocket","",ex2); + } + } + } + + + protected void ThreadSleep(int milltime) + { + try + { + Thread.sleep(milltime); + } + catch (Exception ex) + { + + } + } +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/NetShareBase.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/NetShareBase.java new file mode 100644 index 0000000..4855159 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/NetShareBase.java @@ -0,0 +1,681 @@ +package com.example.HslCommunication.Core.Net; + +import android.util.Log; + +import com.example.HslCommunication.Core.Types.OperateResult; +import com.example.HslCommunication.Core.Utilities.boolWith2Bytes; +import com.example.HslCommunication.Core.Utilities.boolWithBytes; +import com.example.HslCommunication.Core.Utilities.boolWithIntByte; +import com.example.HslCommunication.Core.Utilities.boolWithIntString; +import com.example.HslCommunication.Core.Utilities.Utilities; +import com.example.HslCommunication.Log.LogUtil; +import com.example.HslCommunication.Resources.StringResources; + + +import java.net.Socket; + +/** + * Created by DATHLIN on 2017/11/2. + */ + +public abstract class NetShareBase extends NetBase { + + + /// + /// [自校验] 发送字节数据并确认对方接收完成数据,如果结果异常,则结束通讯 + /// + /// 网络套接字 + /// 头指令 + /// 用户指令 + /// 发送的数据 + /// 用于返回的结果 + /// 发送的进度报告 + /// 失败时存储的额外描述信息 + /// + protected boolean SendBaseAndCheckReceive( + Socket socket, + int headcode, + int customer, + byte[] send, + OperateResult result, + ProgressReport sendReport, + String failedString + ) + { + // 数据处理 + send = NetSupport.CommandBytes(headcode, customer, KeyToken, send); + + Log.i(Utilities.bytes2HexString(send), "SendBaseAndCheckReceive: "); + + // 发送数据 + if (!SendBytesToSocket( + socket, // 套接字 + send, // 发送的字节数据 + result, // 结果信息对象 + failedString // 异常附加对象 + )) + { + send = null; + return false; + } + + // 确认对方是否接收完成 + int remoteReceive = send.length - HslCommunicationCode.HeadByteLength; + Log.i("等待接收数据", "SendBaseAndCheckReceive: "); + + if (!CheckRomoteReceived( + socket, // 套接字 + remoteReceive, // 对方需要接收的长度 + sendReport, // 发送进度报告 + result, // 结果信息对象 + failedString // 异常附加信息 + )) + { + send = null; + return false; + } + + Log.i("对方接收成功", "SendBaseAndCheckReceive: "); + // 对方接收成功 + send = null; + return true; + } + + /// + /// [自校验] 发送字节数据并确认对方接收完成数据,如果结果异常,则结束通讯 + /// + /// 网络套接字 + /// 用户指令 + /// 发送的数据 + /// 用于返回的结果 + /// 发送的进度报告 + /// 异常时记录到日志的附加信息 + /// + protected boolean SendBytesAndCheckReceive( + Socket socket, + int customer, + byte[] send, + OperateResult result, + ProgressReport sendReport, + String failedString + ) + { + if (SendBaseAndCheckReceive( + socket, // 套接字 + HslCommunicationCode.Hsl_Protocol_User_Bytes, // 指示字节数组 + customer, // 用户数据 + send, // 发送数据,该数据还要经过处理 + result, // 结果消息对象 + sendReport, // 发送的进度报告 + failedString // 错误的额外描述 + )) + { + return true; + } + else + { + LogUtil.LogE("SendBytesAndCheckReceive",failedString); + return false; + } + } + + /// + /// [自校验] 直接发送字符串数据并确认对方接收完成数据,如果结果异常,则结束通讯 + /// + /// 网络套接字 + /// 用户指令 + /// 发送的数据 + /// 用于返回的结果 + /// 发送的进度报告 + /// + /// + protected boolean SendStringAndCheckReceive( + Socket socket, + int customer, + String send, + OperateResult result, + ProgressReport sendReport, + String failedString + ) + { + byte[] data =null; + + if(send == null ||send.length() <= 0) + { + + } + else + { + data = send.getBytes(); + } + + if (!SendBaseAndCheckReceive( + socket, // 套接字 + HslCommunicationCode.Hsl_Protocol_User_String, // 指示字符串数据 + customer, // 用户数据 + data, // 字符串的数据 + result, // 结果消息对象 + sendReport, // 发送的进度报告 + failedString // 错误的额外描述 + )) + { + return false; + } + return true; + } + +/* + /// + /// [自校验] 将文件数据发送至套接字,具体发送细节将在继承类中实现,如果结果异常,则结束通讯 + /// + /// 套接字 + /// 文件名称,文件必须存在 + /// 远程端的文件名称 + /// 文件的额外标签 + /// 文件的上传人 + /// 操作结果对象 + /// 发送进度报告 + /// + /// + protected boolean SendFileAndCheckReceive( + Socket socket, + String filename, + String servername, + String filetag, + String fileupload, + OperateResult result, + ProgressReport sendReport, + String failedString + ) + { + // 发送文件名,大小,标签 + File info = new File(filename); + + //FileInfo info = new FileInfo(filename); + + if (!info.exists()) + { + // 如果文件不存在 + if (!SendStringAndCheckReceive(socket, 0, "", result, null, failedString)) return false; + else + { + result.Message = "找不到该文件,请重新确认文件!"; + CloseSocket(socket); + return false; + } + } + + // 文件存在的情况 + Newtonsoft.Json.Linq.JObject json = new Newtonsoft.Json.Linq.JObject + { + { "FileName", new Newtonsoft.Json.Linq.JValue(servername) }, + { "FileSize", new Newtonsoft.Json.Linq.JValue(info.Length) }, + { "FileTag", new Newtonsoft.Json.Linq.JValue(filetag) }, + { "FileUpload", new Newtonsoft.Json.Linq.JValue(fileupload) } + }; + + if (!SendStringAndCheckReceive(socket, 1, json.ToString(), result, null, failedString)) return false; + + + if (!SendFileStreamToSocket(socket, filename, info.Length, result, sendReport, failedString)) + { + return false; + } + + // 检查接收 + // if (!CheckRomoteReceived(socket, info.Length, sendReport, result, failedString)) + // { + // return false; + // } + + return true; + } + + /// + /// [自校验] 将流数据发送至套接字,具体发送细节将在继承类中实现,如果结果异常,则结束通讯 + /// + /// 套接字 + /// 文件名称,文件必须存在 + /// 远程端的文件名称 + /// 文件的额外标签 + /// 文件的上传人 + /// 操作结果对象 + /// 发送进度报告 + /// + /// + protected boolean SendFileAndCheckReceive( + Socket socket, + Stream stream, + String servername, + String filetag, + String fileupload, + OperateResult result, + ProgressReport sendReport, + String failedString + ) + { + // 文件存在的情况 + Newtonsoft.Json.Linq.JObject json = new Newtonsoft.Json.Linq.JObject + { + { "FileName", new Newtonsoft.Json.Linq.JValue(servername) }, + { "FileSize", new Newtonsoft.Json.Linq.JValue(stream.Length) }, + { "FileTag", new Newtonsoft.Json.Linq.JValue(filetag) }, + { "FileUpload", new Newtonsoft.Json.Linq.JValue(fileupload) } + }; + + if (!SendStringAndCheckReceive(socket, 1, json.ToString(), result, null, failedString)) return false; + + + try + { + NetSupport.WriteSocketFromStream(socket, stream, stream.Length, sendReport, true); + } + catch(Exception ex) + { + CloseSocket(socket); + if(LogNet!=null) LogNet.WriteException(failedString, ex); + result.Message = CombineExceptionString(failedString, ex.getLocalizedMessage()); + return false; + } + + // 检查接收 + // if (!CheckRomoteReceived(socket, info.Length, sendReport, result, failedString)) + // { + // return false; + // } + + return true; + }*/ + + + + + /// + /// [自校验] 接收一条完整的同步数据,包含头子节和内容字节,基础的数据,如果结果异常,则结束通讯 + /// + /// 套接字 + /// 头子节 + /// 内容字节 + /// 结果 + /// 接收进度反馈 + /// 失败时用于显示的字符串 + /// + /// result + protected boolWith2Bytes ReceiveAndCheckBytes( + Socket socket, + OperateResult result, + ProgressReport receiveReport, + String failedString + ) + { + boolWith2Bytes value2=new boolWith2Bytes(); + + // 30秒超时接收验证 +// HslTimeOut hslTimeOut = new HslTimeOut() +// { +// DelayTime = 30000, +// IsSuccessful = false, +// StartTime = DateTime.Now, +// WorkSocket = socket, +// }; +// +// ThreadPool.QueueUserWorkItem(new WaitCallback(NetSupport.ThreadPoolCheckTimeOut), hslTimeOut); + + Log.i("准备接收头指令", "ReceiveAndCheckBytes: "); + + boolWithBytes value = ReceiveBytesFromSocket( + socket, // 套接字 + HslCommunicationCode.HeadByteLength, // 头指令长度 + result, // 结果消息对象 + null, // 不报告进度 + false, // 报告是否按照百分比报告 + false, // 不回发接收长度 + true, // 检查是否超时 + failedString // 异常时的附加文本描述 + ); + + if(!value.Result) + { + return value2; + } + + value2.Content = value.Content; + + Log.i("准备检查令牌", "ReceiveAndCheckBytes: "); + + // 检查令牌 + if (!CheckTokenPermission(socket, value.Content, KeyToken, result)) + { + Log.i("令牌检查失败", "ReceiveAndCheckBytes: "); + result.Message = StringResources.TokenCheckFailed; + return value2; + } + + // 接收内容 + byte[] buffer = new byte[4]; + buffer[0]=value.Content[28]; + buffer[1]=value.Content[29]; + buffer[2]=value.Content[30]; + buffer[3]=value.Content[31]; + int contentLength = Utilities.bytes2Int(buffer); + + Log.i("准备接收内容,长度为:"+contentLength, "ReceiveAndCheckBytes: "); + + value =ReceiveBytesFromSocket( + socket, // 套接字 + contentLength, // 内容数据长度 + result, // 结果消息对象 + receiveReport, // 接收进度报告委托 + true, // 按照百分比进行报告数据 + true, // 回发已经接收的数据长度 + false, // 不进行超时检查 + failedString // 异常时附加的文本描述 + ); + + if(!value.Result) + { + return value2; + } + Log.i("内容接收成功", "ReceiveAndCheckBytes: "); + + value2.Content2 = NetSupport.CommandAnalysis(value2.Content, value.Content); + value2.Result=true; + return value2; + } + + + + /// + /// [自校验] 从网络中接收一个字符串数据,如果结果异常,则结束通讯 + /// + /// 套接字 + /// 接收的用户数据 + /// 接收的字节数据 + /// 结果信息对象 + /// 接收数据时的进度报告 + /// 失败时记录日志的字符串 + /// + protected boolWithIntString ReceiveStringFromSocket( + Socket socket, + OperateResult result, + ProgressReport receiveReport, + String failedString + ) + { + boolWithIntString valueString = new boolWithIntString(); + + boolWith2Bytes value2Bytes = ReceiveAndCheckBytes(socket,result, receiveReport, failedString); + + if (!value2Bytes.Result) + { + return valueString; + } + + // check + + byte[] buffer = new byte[4]; + buffer[0]=value2Bytes.Content[0]; + buffer[1]=value2Bytes.Content[1]; + buffer[2]=value2Bytes.Content[2]; + buffer[3]=value2Bytes.Content[3]; + if (Utilities.bytes2Int(buffer) != HslCommunicationCode.Hsl_Protocol_User_String) + { + result.Message = "数据头校验失败!"; + LogUtil.LogE("ReceiveStringFromSocket","数据头校验失败!"); + CloseSocket(socket); + return valueString; + } + + buffer[0]=value2Bytes.Content[4]; + buffer[1]=value2Bytes.Content[5]; + buffer[2]=value2Bytes.Content[6]; + buffer[3]=value2Bytes.Content[7]; + // 分析数据 + valueString.DataInt = Utilities.bytes2Int(buffer); + valueString.DataString = Utilities.byte2String(value2Bytes.Content2); + valueString.Result = true; + return valueString; + } + + /// + /// [自校验] 从网络中接收一串字节数据,如果结果异常,则结束通讯 + /// + /// 套接字 + /// 接收的用户数据 + /// 接收的字节数据 + /// 结果信息对象 + /// 失败时记录日志的字符串 + /// + protected boolWithIntByte ReceiveContentFromSocket( + Socket socket, + OperateResult result, + ProgressReport receiveReport, + String failedString + ) + { + + boolWithIntByte value = new boolWithIntByte(); + + boolWith2Bytes value2Bytes = ReceiveAndCheckBytes(socket,result,null, failedString); + + if (!value2Bytes.Result) + { + return value; + } + + byte[] buffer = new byte[4]; + buffer[0]=value2Bytes.Content[0]; + buffer[1]=value2Bytes.Content[1]; + buffer[2]=value2Bytes.Content[2]; + buffer[3]=value2Bytes.Content[3]; + if (Utilities.bytes2Int(buffer) != HslCommunicationCode.Hsl_Protocol_User_String) + { + result.Message = "数据头校验失败!"; + LogUtil.LogE("ReceiveContentFromSocket","数据头校验失败!"); + CloseSocket(socket); + return value; + } + + buffer[0]=value2Bytes.Content[4]; + buffer[1]=value2Bytes.Content[5]; + buffer[2]=value2Bytes.Content[6]; + buffer[3]=value2Bytes.Content[7]; + // 分析数据 + value.DataInt = Utilities.bytes2Int(buffer); + value.Content = value2Bytes.Content2; + value.Result = true; + return value; + } + +/* + + /// + /// [自校验] 从套接字中接收文件头信息 + /// + /// + /// + /// + /// + /// + /// + /// + /// + protected bool ReceiveFileHeadFromSocket( + Socket socket, + out string filename, + out long size, + out string filetag, + out string fileupload, + OperateResult result, + string failedString = null + ) + { + // 先接收文件头信息 + if (!ReceiveStringFromSocket(socket, out int customer, out string filehead, result, null, failedString)) + { + filename = null; + size = 0; + filetag = null; + fileupload = null; + return false; + } + + // 判断文件是否存在 + if (customer == 0) + { + LogNet?.WriteWarn("对方文件不存在,无法接收!"); + result.Message = StringResources.FileNotExist; + filename = null; + size = 0; + filetag = null; + fileupload = null; + socket?.Close(); + return false; + } + + // 提取信息 + Newtonsoft.Json.Linq.JObject json = Newtonsoft.Json.Linq.JObject.Parse(filehead); + filename = SoftBasic.GetValueFromJsonObject(json, "FileName", ""); + size = SoftBasic.GetValueFromJsonObject(json, "FileSize", 0L); + filetag = SoftBasic.GetValueFromJsonObject(json, "FileTag", ""); + fileupload = SoftBasic.GetValueFromJsonObject(json, "FileUpload", ""); + + return true; + } + + + /// + /// [自校验] 从网络中接收一个文件,如果结果异常,则结束通讯 + /// + /// 网络套接字 + /// 接收文件后保存的文件名 + /// 文件在对方电脑上的文件名 + /// 文件大小 + /// 文件的标识 + /// 文件的上传人 + /// 结果信息对象 + /// 接收进度报告 + /// 失败时的记录日志字符串 + /// + protected bool ReceiveFileFromSocket( + Socket socket, + string savename, + out string filename, + out long size, + out string filetag, + out string fileupload, + OperateResult result, + Action receiveReport, + string failedString = null + ) + { + // 先接收文件头信息 + if (!ReceiveFileHeadFromSocket( + socket, + out filename, + out size, + out filetag, + out fileupload, + result, + failedString + )) + { + return false; + } + + //// 先接收文件头信息 + //if (!ReceiveStringFromSocket(socket, out int customer, out string filehead, result, null, failedString)) + //{ + // filename = null; + // size = 0; + // filetag = null; + // fileupload = null; + // return false; + //} + + //// 判断文件是否存在 + //if (customer == 0) + //{ + // LogNet?.WriteWarn("对方文件不存在,无法接收!"); + // result.Message = StringResources.FileNotExist; + // filename = null; + // size = 0; + // filetag = null; + // fileupload = null; + // socket?.Close(); + // return false; + //} + + //// 提取信息 + //Newtonsoft.Json.Linq.JObject json = Newtonsoft.Json.Linq.JObject.Parse(filehead); + //filename = SoftBasic.GetValueFromJsonObject(json, "FileName", ""); + //size = SoftBasic.GetValueFromJsonObject(json, "FileSize", 0L); + //filetag = SoftBasic.GetValueFromJsonObject(json, "FileTag", ""); + //fileupload = SoftBasic.GetValueFromJsonObject(json, "FileUpload", ""); + + // 接收文件消息 + if (!ReceiveFileSteamFromSocket(socket, savename, size, receiveReport, result, failedString)) + { + return false; + } + + return true; + } + + /// + /// [自校验] 从网络中接收一个文件,写入数据流,如果结果异常,则结束通讯 + /// + /// 网络套接字 + /// 等待写入的数据流 + /// 文件在对方电脑上的文件名 + /// 文件大小 + /// 文件的标识 + /// 文件的上传人 + /// 结果信息对象 + /// 接收进度报告 + /// 失败时的记录日志字符串 + /// + protected bool ReceiveFileFromSocket( + Socket socket, + Stream stream, + out string filename, + out long size, + out string filetag, + out string fileupload, + OperateResult result, + Action receiveReport, + string failedString = null + ) + { + // 先接收文件头信息 + if (!ReceiveFileHeadFromSocket( + socket, + out filename, + out size, + out filetag, + out fileupload, + result, + failedString + )) + { + return false; + } + + + try + { + NetSupport.WriteStreamFromSocket(socket, stream, size, receiveReport, true); + return true; + } + catch (Exception ex) + { + result.Message = ex.Message; + socket?.Close(); + return false; + } + } +*/ + + + +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/NetSupport.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/NetSupport.java new file mode 100644 index 0000000..1a528d8 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/NetSupport.java @@ -0,0 +1,338 @@ +package com.example.HslCommunication.Core.Net; + +import com.example.HslCommunication.Core.Types.HslTimeOut; +import com.example.HslCommunication.Core.Utilities.Utilities; + +import java.io.DataOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.util.Date; +import java.io.DataInputStream; +import java.util.UUID; + +/** + * Created by DATHLIN on 2017/11/1. + */ + +public class NetSupport { + + private static final int SocketBufferSize = 4096; + + + + public static void ThreadPoolCheckConnect(HslTimeOut timeout, int millisecond) { + while (!timeout.IsSuccessful) { + if ((new Date().getTime() - timeout.StartTime.getTime()) > millisecond) { + // 连接超时或是验证超时 + if (!timeout.IsSuccessful) { + try { + if (timeout.WorkSocket != null) { + timeout.WorkSocket.close(); + } + } catch (java.io.IOException ex) { + // 不处理,放弃 + } + } + break; + } + } + } + + public static boolean IsTwoBytesEquel(byte[] b1, int start1, byte[] b2, int start2, int length) { + if (b1 == null || b2 == null) return false; + for (int i = 0; i < length; i++) { + if (b1[i + start1] != b2[i + start2]) { + return false; + } + } + return true; + } + + public static boolean CheckTokenEquel(byte[] head, UUID token) + { + return IsTwoBytesEquel(head, 12, Utilities.UUID2Byte(token), 0, 16); + } + + + + public static byte[] ReadBytesFromSocket(Socket socket, int receive, ProgressReport report, boolean reportByPercent, boolean response) throws java.io.IOException + { + byte[] bytes_receive = new byte[receive]; + int count_receive = 0; + long percent = 0; + + DataInputStream input = new DataInputStream(socket.getInputStream()); + DataOutputStream output = new DataOutputStream(socket.getOutputStream()); + + while (count_receive < receive) { + // 分割成4KB来接收数据 + int receive_length = 0; + if ((receive - count_receive) >= SocketBufferSize) { + receive_length = SocketBufferSize; + } else { + receive_length = (receive - count_receive); + } + + count_receive += input.read(bytes_receive, count_receive, receive_length); + + if (reportByPercent) { + long percentCurrent = (long) count_receive * 100 / receive; + if (percent != percentCurrent) { + percent = percentCurrent; + // 报告进度 + if (report != null) report.Report(count_receive, receive); + } + } else { + // 报告进度 + if (report != null) report.Report(count_receive, receive); + } + + // 回发进度 + if (response) output.write(Utilities.long2Bytes((long) count_receive)); + } + + return bytes_receive; + } + + + + public static byte[] ReadBytesFromSocket(Socket socket, int receive) throws java.io.IOException { + return ReadBytesFromSocket(socket, receive, null, false, false); + } + + + + /// + /// 读取套接字并且写入流 + /// + /// 文件流 + /// 连接的套接字 + /// 返回的文件长度 + /// 发送的进度报告 + /// + public static void WriteStreamFromSocket(Socket socket, OutputStream stream, long receive, ProgressReport report, boolean reportByPercent) throws java.io.IOException + { + byte[] buffer = new byte[SocketBufferSize]; + long count_receive = 0; + long percent = 0; + + DataInputStream input = new DataInputStream(socket.getInputStream()); + DataOutputStream output = new DataOutputStream(socket.getOutputStream()); + + while (count_receive < receive) + { + // 分割成4KB来接收数据 + int current = input.read(buffer, 0, SocketBufferSize); + + count_receive += current; + stream.write(buffer, 0, current); + if (reportByPercent) + { + long percentCurrent = count_receive * 100 / receive; + if (percent != percentCurrent) + { + percent = percentCurrent; + // 报告进度 + if (report != null) report.Report(count_receive, receive); + } + } + else + { + // 报告进度 + if (report != null) report.Report(count_receive, receive); + } + // 回发进度 + output.write(Utilities.long2Bytes(count_receive)); + } + buffer = null; + } + + + + + /// + /// 读取流并将数据写入socket + /// + /// 文件流 + /// 连接的套接字 + /// 返回的文件长度 + /// 发送的进度报告 + /// + public static void WriteSocketFromStream(Socket socket, InputStream stream, long length, ProgressReport report, boolean reportByPercent) throws java.io.IOException + { + byte[] buffer = new byte[SocketBufferSize]; + long count_send = 0; + long percent = 0; + + DataInputStream input = new DataInputStream(socket.getInputStream()); + DataOutputStream output = new DataOutputStream(socket.getOutputStream()); + + while (count_send < length) + { + int count = stream.read(buffer, 0, SocketBufferSize); + count_send += count; + + + output.write(buffer, 0, count); + + while (count_send != Utilities.bytes2Long(ReadBytesFromSocket(socket, 8))); + + long received = count_send; + + if (reportByPercent) + { + long percentCurrent = received * 100 / length; + if (percent != percentCurrent) + { + percent = percentCurrent; + // 报告进度 + if (report != null) report.Report(received, length); + } + } + else + { + // 报告进度 + if (report != null) report.Report(received, length); + } + + // 双重接收验证 + if (count == 0) + { + break; + } + } + + buffer = null; + } + + + + public static void CheckSendBytesReceived(Socket socket, long length, ProgressReport report, boolean reportByPercent) throws java.io.IOException + { + long remoteNeedReceive = 0; + long percent = 0; + + // 确认服务器的数据是否接收完成 + while (remoteNeedReceive < length) + { + remoteNeedReceive = Utilities.bytes2Long(ReadBytesFromSocket(socket, 8)); + if (reportByPercent) + { + long percentCurrent = remoteNeedReceive * 100 / length; + if (percent != percentCurrent) + { + percent = percentCurrent; + // 报告进度 + if (report != null) report.Report(remoteNeedReceive, length); + } + } + else + { + // 报告进度 + if (report != null) report.Report(remoteNeedReceive, length); + } + } + } + + + /* + + 发送字节数据的最终命令 + + */ + + public static byte[] CommandBytes(int customer, UUID token, byte[] data) + { + return CommandBytes(HslCommunicationCode.Hsl_Protocol_User_Bytes, customer, token, data); + } + + + /* + + 生成发送文本数据的最终命令 + + */ + + public static byte[] CommandBytes(int customer, UUID token, String data) + { + if (data == null) return CommandBytes(HslCommunicationCode.Hsl_Protocol_User_String, customer, token, null); + else return CommandBytes(HslCommunicationCode.Hsl_Protocol_User_String, customer, token, Utilities.string2Byte(data)); + } + + /* + + 生成最终的发送命令 + + */ + + public static byte[] CommandBytes(int command, int customer, UUID token, byte[] data) + { + byte[] _temp = null; + int _zipped = HslCommunicationCode.Hsl_Protocol_NoZipped; + int _sendLength = 0; + if (data == null) + { + _temp = new byte[HslCommunicationCode.HeadByteLength]; + } + else + { + // 加密 + data = HslSecurity.ByteEncrypt(data); + if (data.length > 10240) + { + // 10K以上的数据,进行数据压缩 + data = HslZipped.CompressBytes(data); + _zipped = HslCommunicationCode.Hsl_Protocol_Zipped; + } + _temp = new byte[HslCommunicationCode.HeadByteLength + data.length]; + _sendLength = data.length; + } + + Utilities.int2Bytes(command); + + System.arraycopy(Utilities.int2Bytes(command),0,_temp,0,4); + System.arraycopy(Utilities.int2Bytes(customer),0,_temp,4,4); + System.arraycopy(Utilities.int2Bytes(_zipped),0,_temp,8,4); + System.arraycopy(Utilities.UUID2Byte(token),0,_temp,12,16); + System.arraycopy(Utilities.int2Bytes(_sendLength),0,_temp,28,4); + if (_sendLength > 0) + { + System.arraycopy(data,0,_temp,32,_sendLength); + } + return _temp; + } + + + /* + + 从接收的数据命令开始解析 + + */ + + public static byte[] CommandAnalysis(byte[] head, byte[] content) + { + if (content != null) + { + byte[] buffer = new byte[4]; + buffer[0] = head[8]; + buffer[1] = head[9]; + buffer[2] = head[10]; + buffer[3] = head[11]; + + int _zipped = Utilities.bytes2Int(buffer); + // 先进行解压 + if (_zipped == HslCommunicationCode.Hsl_Protocol_Zipped) + { + content = HslZipped.Decompress(content); + } + // 进行解密 + return HslSecurity.ByteDecrypt(content); + } + else + { + return null; + } + } + +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/ProgressReport.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/ProgressReport.java new file mode 100644 index 0000000..29b7a7e --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Net/ProgressReport.java @@ -0,0 +1,16 @@ +package com.example.HslCommunication.Core.Net; + +/** + * Created by DATHLIN on 2017/11/1. + */ + + +public abstract class ProgressReport { + + + public void Report(long current,long totle) + { + + } + +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Types/HslTimeOut.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Types/HslTimeOut.java new file mode 100644 index 0000000..83db408 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Types/HslTimeOut.java @@ -0,0 +1,26 @@ +package com.example.HslCommunication.Core.Types; + +import java.net.Socket; +import java.util.Date; + +/** + * Created by DATHLIN on 2017/11/1. + */ + +public class HslTimeOut { + + + public HslTimeOut() + { + StartTime = new Date(); + IsSuccessful = false; + } + + public Date StartTime=null; + + public boolean IsSuccessful=false; + + public int DelayTime=5000; + + public Socket WorkSocket=null; +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Types/NetHandle.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Types/NetHandle.java new file mode 100644 index 0000000..4ddad35 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Types/NetHandle.java @@ -0,0 +1,109 @@ +package com.example.HslCommunication.Core.Types; + +import com.example.HslCommunication.Core.Utilities.Utilities; + +/** + * Created by DATHLIN on 2017/11/2. + */ + +public final class NetHandle { + + + /// + /// 初始化一个暗号对象 + /// + public NetHandle(int value) + { + byte[] buffer = Utilities.int2Bytes(value); + + m_CodeMajor = buffer[3]; + m_CodeMinor = buffer[2]; + m_CodeIdentifier = Utilities.byte2Short(buffer,0); + + + m_CodeValue = value; + } + + + /// + /// 根据三个值来初始化暗号对象 + /// + /// 主暗号 + /// 次暗号 + /// 暗号编号 + public NetHandle(int major, int minor, int identifier) + { + m_CodeValue = 0; + + byte[] buffer_major=Utilities.int2Bytes(major); + byte[] buffer_minor=Utilities.int2Bytes(minor); + byte[] buffer_identifier=Utilities.int2Bytes(identifier); + + m_CodeMajor = buffer_major[0]; + m_CodeMinor = buffer_minor[0]; + m_CodeIdentifier = Utilities.byte2Short(buffer_identifier,0); + + byte[] buffer = new byte[4]; + buffer[3] = m_CodeMajor; + buffer[2] = m_CodeMinor; + buffer[1] = buffer_identifier[1]; + buffer[0] = buffer_identifier[0]; + + m_CodeValue = Utilities.bytes2Int(buffer); + } + + + /// + /// 完整的暗号值 + /// + private int m_CodeValue; + + /// + /// 主暗号分类0-255 + /// + private byte m_CodeMajor; + + /// + /// 次要的暗号分类0-255 + /// + private byte m_CodeMinor; + + /// + /// 暗号的编号分类0-65535 + /// + private short m_CodeIdentifier; + + + + /// + /// 完整的暗号值 + /// + public int get_CodeValue(){ + return m_CodeValue; + } + + /// + /// 主暗号分类0-255 + /// + public byte get_CodeMajor() { + return m_CodeMajor; + } + + /// + /// 次要的暗号分类0-255 + /// + public byte get_CodeMinor() { + return m_CodeMinor; + } + + /// + /// 暗号的编号分类0-65535 + /// + public short get_CodeIdentifier() { + return m_CodeIdentifier; + } + + + + +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Types/OperateResult.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Types/OperateResult.java new file mode 100644 index 0000000..d5d8874 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Types/OperateResult.java @@ -0,0 +1,38 @@ +package com.example.HslCommunication.Core.Types; + +/** + * Created by DATHLIN on 2017/11/1. + */ + +public class OperateResult { + + /// + /// 指示本次访问是否成功 + /// + public boolean IsSuccess =false; + + + /// + /// 具体的错误描述 + /// + public String Message = "Unknown Errors"; + /// + /// 具体的错误代码 + /// + public int ErrorCode = 10000; + + /// + /// 消息附带的额外信息 + /// + public Object Tag =null; + + /// + /// 获取错误代号及文本描述 + /// + /// + public String ToMessageShowString() + { + return "错误代码:"+ErrorCode +"\r\n错误信息:"+Message; + } + +} \ No newline at end of file diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Types/OperateResultBytes.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Types/OperateResultBytes.java new file mode 100644 index 0000000..bc2d1ba --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Types/OperateResultBytes.java @@ -0,0 +1,9 @@ +package com.example.HslCommunication.Core.Types; + +/** + * Created by DATHLIN on 2017/11/1. + */ + +public class OperateResultBytes extends OperateResult { + public byte[] Content =null; +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Types/OperateResultString.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Types/OperateResultString.java new file mode 100644 index 0000000..7f7bea9 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Types/OperateResultString.java @@ -0,0 +1,11 @@ +package com.example.HslCommunication.Core.Types; + +/** + * Created by DATHLIN on 2017/11/1. + */ + + + +public class OperateResultString extends OperateResult { + public String Content = null; +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/Utilities.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/Utilities.java new file mode 100644 index 0000000..f4c2fd8 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/Utilities.java @@ -0,0 +1,172 @@ +package com.example.HslCommunication.Core.Utilities; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.UUID; + +/** + * Created by DATHLIN on 2017/11/1. + */ + + + +public class Utilities { + + public static byte[] int2Bytes(int num) { + byte[] byteNum = new byte[4]; + for (int ix = 0; ix < 4; ++ix) { + int offset = 32 - (ix + 1) * 8; + byteNum[3-ix] = (byte) ((num >> offset) & 0xff); + } + return byteNum; + } + + public static int bytes2Int(byte[] byteNum) { + int num = 0; + for (int ix = 0; ix < 4; ++ix) { + num <<= 8; + num |= (byteNum[3-ix] & 0xff); + } + return num; + } + + public static byte int2OneByte(int num) { + return (byte) (num & 0x000000ff); + } + + public static int oneByte2Int(byte byteNum) { + //针对正数的int + return byteNum > 0 ? byteNum : (128 + (128 + byteNum)); + } + + public static byte[] long2Bytes(long num) { + byte[] byteNum = new byte[8]; + for (int ix = 0; ix < 8; ++ix) { + int offset = 64 - (ix + 1) * 8; + byteNum[7-ix] = (byte) ((num >> offset) & 0xff); + } + return byteNum; + } + + public static long bytes2Long(byte[] byteNum) { + long num = 0; + for (int ix = 0; ix < 8; ++ix) { + num <<= 8; + num |= (byteNum[7-ix] & 0xff); + } + return num; + } + + public static UUID Byte2UUID(byte[] data) { + if (data.length != 16) { + throw new IllegalArgumentException("Invalid UUID byte[]"); + } + long msb = 0; + long lsb = 0; + for (int i = 0; i < 8; i++) + msb = (msb << 8) | (data[i] & 0xff); + for (int i = 8; i < 16; i++) + lsb = (lsb << 8) | (data[i] & 0xff); + + return new UUID(msb, lsb); + } + + public static byte[] UUID2Byte(UUID uuid) { + ByteArrayOutputStream ba = new ByteArrayOutputStream(16); + DataOutputStream da = new DataOutputStream(ba); + try { + da.writeLong(uuid.getMostSignificantBits()); + da.writeLong(uuid.getLeastSignificantBits()); + } + catch (IOException e) { + e.printStackTrace(); + } + byte[] buffer = ba.toByteArray(); + // 进行错位 + byte temp=buffer[0]; + buffer[0] = buffer[3]; + buffer[3] =temp; + temp=buffer[1]; + buffer[1]=buffer[2]; + buffer[2]=temp; + + temp = buffer[4]; + buffer[4]=buffer[5]; + buffer[5] =temp; + + temp = buffer[6]; + buffer[6]=buffer[7]; + buffer[7] =temp; + + return buffer; + } + + public static short byte2Short(byte[] b, int index) { + return (short) (((b[index + 0] << 8) | b[index + 1] & 0xff)); + } + + + public static byte[] short2Byte(short s) { + byte[] targets = new byte[2]; + for (int i = 0; i < 2; i++) { + int offset = (targets.length - 1 - i) * 8; + targets[1-i] = (byte) ((s >>> offset) & 0xff); + } + return targets; + } + + public static byte[] string2Byte(String str) { + if (str == null) { + return null; + } + byte[] byteArray; + try { + byteArray = str.getBytes("unicode"); + } catch (Exception ex) { + byteArray = str.getBytes(); + } + + for(int i=0;i>> 4 & 0xf]; + buf[index++] = HEX_CHAR[b & 0xf]; + } + + return new String(buf); + } +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWith2Bytes.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWith2Bytes.java new file mode 100644 index 0000000..e036dd1 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWith2Bytes.java @@ -0,0 +1,9 @@ +package com.example.HslCommunication.Core.Utilities; + +/** + * Created by DATHLIN on 2017/11/2. + */ + +public class boolWith2Bytes extends boolWithBytes { + public byte[] Content2=null; +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithBytes.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithBytes.java new file mode 100644 index 0000000..63d3173 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithBytes.java @@ -0,0 +1,14 @@ +package com.example.HslCommunication.Core.Utilities; + +/** + * Created by DATHLIN on 2017/11/2. + */ + + +public class boolWithBytes extends boolWithNone { + + + public byte[] Content=null; + + +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithIntByte.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithIntByte.java new file mode 100644 index 0000000..70b0d63 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithIntByte.java @@ -0,0 +1,9 @@ +package com.example.HslCommunication.Core.Utilities; + +/** + * Created by DATHLIN on 2017/11/2. + */ + +public class boolWithIntByte extends boolWithBytes { + public int DataInt=0; +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithIntString.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithIntString.java new file mode 100644 index 0000000..733e027 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithIntString.java @@ -0,0 +1,14 @@ +package com.example.HslCommunication.Core.Utilities; + +/** + * Created by DATHLIN on 2017/11/2. + */ + +public class boolWithIntString extends boolWithNone { + + + public int DataInt=0; + + + public String DataString=null; +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithNone.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithNone.java new file mode 100644 index 0000000..139ba50 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithNone.java @@ -0,0 +1,23 @@ +package com.example.HslCommunication.Core.Utilities; + +/** + * Created by DATHLIN on 2017/11/3. + */ + + + + +/* +* +* 结果类的基础,提供一个boolen +* +* +* */ + +public class boolWithNone { + + /* + 返回真还是否 + */ + public boolean Result = false; +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithSiemens.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithSiemens.java new file mode 100644 index 0000000..10bf9cc --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithSiemens.java @@ -0,0 +1,16 @@ +package com.example.HslCommunication.Core.Utilities; + +/** + * Created by DATHLIN on 2017/11/3. + */ + +public class boolWithSiemens extends boolWithNone { + + + public byte type=0; + + public int startAddress=0; + + public short dbAddress=0; + +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithSocket.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithSocket.java new file mode 100644 index 0000000..adc5303 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithSocket.java @@ -0,0 +1,11 @@ +package com.example.HslCommunication.Core.Utilities; + +import java.net.Socket; + +/** + * Created by hsl20 on 2017/11/4. + */ + +public class boolWithSocket extends boolWithNone { + public Socket Socket=null; +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithString.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithString.java new file mode 100644 index 0000000..cab278b --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Core/Utilities/boolWithString.java @@ -0,0 +1,10 @@ +package com.example.HslCommunication.Core.Utilities; + +/** + * Created by DATHLIN on 2017/11/2. + */ + +public class boolWithString extends boolWithNone { + + public String Content=null; +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Enthernet/AsyncStateOne.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Enthernet/AsyncStateOne.java new file mode 100644 index 0000000..4edfd73 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Enthernet/AsyncStateOne.java @@ -0,0 +1,135 @@ +package com.example.HslCommunication.Enthernet; + +import com.example.HslCommunication.Core.Net.HslCommunicationCode; + +import java.net.Socket; +import java.util.Date; +import java.util.UUID; + +/** + * Created by hsl20 on 2017/11/4. + */ + +public class AsyncStateOne { + + + /// + /// 实例化一个对象 + /// + public AsyncStateOne() { + ClientUniqueID = UUID.randomUUID().toString(); + } + + /// + /// IP地址 + /// + private String IpAddress = ""; + + public String getIpAddress() { + return IpAddress; + } + + private void setIpAddress(String ipAddress) { + IpAddress = ipAddress; + } + + + /* + 端口号 + */ + private int IpPort = 10000; + + public int getIpPort() { + return IpPort; + } + + private void setIpPort(int ipPort) { + IpPort = ipPort; + } + + + /* + 登录的别名 + */ + private String LoginAlias = ""; + + public String getLoginAlias() { + return LoginAlias; + } + + public void setLoginAlias(String loginAlias) { + LoginAlias = loginAlias; + } + + + /* + 心跳验证的时间点 + */ + private Date HeartTime=new Date(); + public Date getHeartTime() { + return HeartTime; + } + + public void setHeartTime(Date heartTime) { + HeartTime = heartTime; + } + + + /* + 客户端类别 + */ + private String ClientType=""; + public void setClientType(String clientType) { + ClientType = clientType; + } + + + public String getClientType() { + return ClientType; + } + + + /* + 客户端的唯一标识 + */ + private String ClientUniqueID=""; + public String getClientUniqueID() { + return ClientUniqueID; + } + + public void setClientUniqueID(String clientUniqueID) { + ClientUniqueID = clientUniqueID; + } + + + + /// + /// 指令头缓存 + /// + byte[] BytesHead = new byte[HslCommunicationCode.HeadByteLength]; + /// + /// 已经接收的指令头长度 + /// + int AlreadyReceivedHead = 0; + /// + /// 数据内容缓存 + /// + byte[] BytesContent = null; + /// + /// 已经接收的数据内容长度 + /// + int AlreadyReceivedContent = 0; + + /// + /// 清除本次的接收内容 + /// + void Clear() { + BytesHead = new byte[HslCommunicationCode.HeadByteLength]; + AlreadyReceivedHead = 0; + BytesContent = null; + AlreadyReceivedContent = 0; + } + + + Socket WorkSocket=null; +} \ No newline at end of file diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Enthernet/NetComplexClient.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Enthernet/NetComplexClient.java new file mode 100644 index 0000000..008759c --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Enthernet/NetComplexClient.java @@ -0,0 +1,442 @@ +package com.example.HslCommunication.Enthernet; + +import com.example.HslCommunication.Core.Net.HslCommunicationCode; +import com.example.HslCommunication.Core.Net.NetShareBase; +import com.example.HslCommunication.Core.Net.NetSupport; +import com.example.HslCommunication.Core.Types.NetHandle; +import com.example.HslCommunication.Core.Types.OperateResult; +import com.example.HslCommunication.Core.Utilities.Utilities; +import com.example.HslCommunication.Core.Utilities.boolWith2Bytes; +import com.example.HslCommunication.Core.Utilities.boolWithSocket; +import com.example.HslCommunication.Log.LogUtil; +import com.example.HslCommunication.Resources.StringResources; + +import java.net.Socket; +import java.util.Date; + +/** + * Created by hsl20 on 2017/11/4. + */ + +public class NetComplexClient extends NetShareBase { + + + + /// + /// 客户端的核心连接块 + /// + private AsyncStateOne stateone = new AsyncStateOne(); + /// + /// 客户端系统是否启动 + /// + public boolean Is_Client_Start = false; + + /// + /// 重连接失败的次数 + /// + public int Connect_Failed_Count = 0; + /// + /// 指示客户端是否处于正在连接服务器中 + /// + private boolean Is_Client_Connecting = false; + /// + /// 登录服务器的判断锁 + /// + private Object lock_connecting = new Object(); + /// + /// 客户端登录的标识名称,可以为ID号,也可以为登录名 + /// + public String ClientAlias = ""; + /// + /// 远程服务器的IP地址和端口 + /// + public String ServerIp = "127.0.0.1"; + /* + 远程服务器的端口 + */ + public int ServerPort = 10000; + + /// + /// 服务器的时间,自动实现和服务器同步 + /// + private Date ServerTime = new Date(); + /// + /// 系统与服务器的延时时间,单位毫秒 + /// + private int DelayTime =0; + + + + public void LoginSuccess() + { + + } + + public void LoginFailed(int times) + { + + } + + public void MessageAlerts(String msg) + { + + } + + public void BeforReConnected() + { + + } + + public void AcceptString(NetHandle handle, String msg) + { + + } + + public void AcceptByte( NetHandle handle, byte[] msg) + { + + } + + + private boolean IsQuie = false; + + /// + /// 关闭该客户端引擎 + /// + public void ClientClose() { + IsQuie = true; + if (Is_Client_Start) + SendBytes(stateone, NetSupport.CommandBytes(HslCommunicationCode.Hsl_Protocol_Client_Quit, 0, KeyToken, null)); + + if (thread_heart_check != null) thread_heart_check.interrupt(); + Is_Client_Start = false; + + + ThreadSleep(10); + + CloseSocket(stateone.WorkSocket); + LogUtil.LogD("ClientClose","Client Close."); + } + /// + /// 启动客户端引擎,连接服务器系统 + /// + public void ClientStart() + { + if (Is_Client_Start) return; + Thread thread_login = new Thread(new Runnable() { + @Override + public void run() { + ThreadLogin(); + } + }); + thread_login.start(); + LogUtil.LogD("ClientStart","Client Start."); + + if (thread_heart_check == null) + { + thread_heart_check = new Thread(new Runnable() { + @Override + public void run() { + ThreadHeartCheck(); + } + }); + thread_heart_check.start(); + } + } + private void ThreadLogin() + { + synchronized (lock_connecting) + { + if (Is_Client_Connecting) return; + Is_Client_Connecting = true; + } + + + if (Connect_Failed_Count == 0) + { + MessageAlerts("正在连接服务器..."); + } + else + { + int count = 10; + while (count > 0) + { + if (IsQuie) return; + MessageAlerts("连接断开,等待" + count-- + "秒后重新连接"); + ThreadSleep(1000); + } + MessageAlerts("正在尝试第" + Connect_Failed_Count + "次连接服务器..."); + } + + + stateone.setHeartTime(new Date()); + LogUtil.LogD("ThreadLogin","Begin Connect Server, Times: " + Connect_Failed_Count); + + + OperateResult result = new OperateResult(); + + Socket socket=null; + boolWithSocket valueSocket = CreateSocketAndConnect(ServerIp,ServerPort,result); + if(!valueSocket.Result) + { + Connect_Failed_Count++; + Is_Client_Connecting = false; + LoginFailed(Connect_Failed_Count); + LogUtil.LogW("ThreadLogin","Connected Failed, Times: " + Connect_Failed_Count); + // 连接失败,重新连接服务器 + ReconnectServer(); + return; + } + + socket = valueSocket.Socket; + + // 连接成功,发送数据信息 + if(!SendStringAndCheckReceive( + socket, + 1, + ClientAlias, + result, + null, + null + )) + { + Connect_Failed_Count++; + Is_Client_Connecting = false; + LogUtil.LogD("ThreadLogin","Login Server Failed, Times: " + Connect_Failed_Count); + LoginFailed(Connect_Failed_Count); + // 连接失败,重新连接服务器 + ReconnectServer(); + return; + } + + // 登录成功 + Connect_Failed_Count = 0; + //stateone.IpEndPoint = (IPEndPoint)socket.RemoteEndPoint; + stateone.setClientType(ClientAlias); + stateone.WorkSocket = socket; + //stateone.WorkSocket.BeginReceive(stateone.BytesHead, stateone.AlreadyReceivedHead, + //stateone.BytesHead.Length - stateone.AlreadyReceivedHead, SocketFlags.None, + //new AsyncCallback(HeadReceiveCallback), stateone); + + Thread receive = new Thread(new Runnable() { + @Override + public void run() { + ThreadReceiveBackground(); + } + }); + receive.start(); + + + + // 发送一条验证消息 + byte[] bytesTemp = new byte[16]; + + //BitConverter.GetBytes(DateTime.Now.Ticks).CopyTo(bytesTemp, 0); + SendBytes(stateone, NetSupport.CommandBytes(HslCommunicationCode.Hsl_Protocol_Check_Secends, 0, KeyToken, bytesTemp)); + + + stateone.setHeartTime(new Date()); + Is_Client_Start = true; + LoginSuccess(); + + LogUtil.LogD("ThreadLogin","Login Server Success, Times: " + Connect_Failed_Count); + + Is_Client_Connecting = false; + + ThreadSleep(1000); + } + + + + private void ThreadReceiveBackground() + { + while (true) + { + OperateResult result = new OperateResult(); + boolWith2Bytes value = ReceiveAndCheckBytes(stateone.WorkSocket, result, null,null); + + if (!value.Result) + { + continue; + } + + // 数据处理 + byte[] buffer1= new byte[4]; + buffer1[0] = value.Content[0]; + buffer1[1] = value.Content[1]; + buffer1[2] = value.Content[2]; + buffer1[3] = value.Content[3]; + + byte[] buffer2= new byte[4]; + buffer2[0] = value.Content[4]; + buffer2[1] = value.Content[5]; + buffer2[2] = value.Content[6]; + buffer2[3] = value.Content[7]; + + int protocol = Utilities.bytes2Int(buffer1); + int customer = Utilities.bytes2Int(buffer2); + + DataProcessingCenter(null,protocol,customer,value.Content2); + } + } + + + // private bool Is_reconnect_server = false; + // private object lock_reconnect_server = new object(); + + + private void ReconnectServer() + { + // 是否连接服务器中,已经在连接的话,则不再连接 + if (Is_Client_Connecting) return; + // 是否退出了系统,退出则不再重连 + if (IsQuie) return; + + LogUtil.LogI("ReconnectServer","Prepare ReConnect Server."); + + // 触发连接失败,重连系统前错误 + BeforReConnected(); + CloseSocket(stateone.WorkSocket); + + Thread thread_login = new Thread(new Runnable() { + @Override + public void run() { + ThreadLogin(); + } + }); + thread_login.start(); + } + + + /// + /// 通信出错后的处理 + /// + /// + /// + void SocketReceiveException(AsyncStateOne receive, Exception ex) + { + if (ex.getMessage().contains(StringResources.SocketRemoteCloseException)) + { + // 异常掉线 + ReconnectServer(); + } + else + { + // MessageAlerts?.Invoke("数据接收出错:" + ex.Message); + } + + LogUtil.LogD("SocketReceiveException","Socket Excepiton Occured."); + } + + + /// + /// 服务器端用于数据发送文本的方法 + /// + /// 用户自定义的命令头 + /// 发送的文本 + public void Send(NetHandle customer, String str) + { + if (Is_Client_Start) + { + SendBytes(stateone, NetSupport.CommandBytes(customer.get_CodeValue(), KeyToken, str)); + } + } + /// + /// 服务器端用于发送字节的方法 + /// + /// 用户自定义的命令头 + /// 实际发送的数据 + public void Send(NetHandle customer, byte[] bytes) + { + if (Is_Client_Start) + { + SendBytes(stateone, NetSupport.CommandBytes(customer.get_CodeValue(), KeyToken, bytes)); + } + } + + private void SendBytes(final AsyncStateOne stateone, final byte[] content) + { + Thread thread_login = new Thread(new Runnable() { + @Override + public void run() { + try { + stateone.WorkSocket.getOutputStream().write(content); + } catch (Exception ex) { + + } + } + }); + thread_login.start(); + //SendBytesAsync(stateone, content); + } + + /// + /// 客户端的数据处理中心 + /// + /// + /// + /// + /// + void DataProcessingCenter(AsyncStateOne receive, int protocol, int customer, byte[] content) + { + if (protocol == HslCommunicationCode.Hsl_Protocol_Check_Secends) + { + //Date dt = new Date(BitConverter.ToInt64(content, 0)); + //ServerTime = new Date(BitConverter.ToInt64(content, 8)); + //DelayTime = (int)(new Date() - dt).TotalMilliseconds; + stateone.setHeartTime(new Date()); + // MessageAlerts?.Invoke("心跳时间:" + DateTime.Now.ToString()); + } + else if (protocol == HslCommunicationCode.Hsl_Protocol_Client_Quit) + { + // 申请了退出 + } + else if (protocol == HslCommunicationCode.Hsl_Protocol_User_Bytes) + { + // 接收到字节数据 + AcceptByte(new NetHandle(customer), content); + } + else if (protocol == HslCommunicationCode.Hsl_Protocol_User_String) + { + // 接收到文本数据 + String str = Utilities.byte2String(content); + AcceptString(new NetHandle(customer), str); + } + } + + + private Thread thread_heart_check = null; + + /// + /// 心跳线程的方法 + /// + private void ThreadHeartCheck() + { + + ThreadSleep(2000); + while (true) + { + ThreadSleep(1000); + + if (!IsQuie) + { + byte[] send = new byte[16]; + System.arraycopy(Utilities.long2Bytes(new Date().getTime()),0,send,0,8); + SendBytes(stateone, NetSupport.CommandBytes(HslCommunicationCode.Hsl_Protocol_Check_Secends, 0, KeyToken, send)); + double timeSpan = (new Date().getTime() - stateone.getHeartTime().getTime())/1000; + if (timeSpan > 1 * 8)//8次没有收到失去联系 + { + LogUtil.LogD("ThreadHeartCheck","Heart Check Failed int "+timeSpan+" Seconds."); + ReconnectServer(); + ThreadSleep(1000); + } + } + else + { + break; + } + } + } + + +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Enthernet/NetSimplifyClient.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Enthernet/NetSimplifyClient.java new file mode 100644 index 0000000..1b0d31e --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Enthernet/NetSimplifyClient.java @@ -0,0 +1,137 @@ +package com.example.HslCommunication.Enthernet; + +import com.example.HslCommunication.Core.Net.HslCommunicationCode; +import com.example.HslCommunication.Core.Net.NetShareBase; +import com.example.HslCommunication.Core.Net.ProgressReport; +import com.example.HslCommunication.Core.Utilities.boolWith2Bytes; +import com.example.HslCommunication.Core.Utilities.Utilities; +import com.example.HslCommunication.Core.Types.NetHandle; +import com.example.HslCommunication.Core.Types.OperateResultBytes; +import com.example.HslCommunication.Core.Types.OperateResultString; +import com.example.HslCommunication.Core.Utilities.boolWithSocket; +import com.example.HslCommunication.Resources.StringResources; + +import java.io.InputStream; +import java.net.Socket; +import java.util.UUID; + +/** + * Created by DATHLIN on 2017/11/2. + */ + +public final class NetSimplifyClient extends NetShareBase { + + + + /// + /// 实例化一个客户端的对象,用于和服务器通信 + /// + public NetSimplifyClient(String ipAddress, int port, UUID token) + { + m_ipAddress = ipAddress; + m_port = port; + KeyToken = token; + } + + private String m_ipAddress="127.0.0.1"; + private int m_port=10000; + + /// + /// 客户端向服务器进行请求,请求字符串数据 + /// + /// 用户的指令头 + /// 发送数据 + /// 发送数据时的进度报告 + /// 接收数据时的进度报告 + /// + public OperateResultString ReadFromServer( + NetHandle customer, + String send, + ProgressReport sendStatus, + ProgressReport receiveStatus + ) + { + OperateResultString result = new OperateResultString(); + byte[] data = Utilities.string2Byte(send); + OperateResultBytes temp = ReadFromServerBase(HslCommunicationCode.Hsl_Protocol_User_String, customer.get_CodeValue(), data, sendStatus, receiveStatus); + result.IsSuccess = temp.IsSuccess; + result.ErrorCode = temp.ErrorCode; + result.Message = temp.Message; + if (temp.IsSuccess) + { + result.Content = Utilities.byte2String(temp.Content); + } + temp = null; + return result; + } + + + /// + /// 客户端向服务器进行请求,请求字节数据 + /// + /// 用户的指令头 + /// + /// 发送数据的进度报告 + /// 接收数据的进度报告 + /// + public OperateResultBytes ReadFromServer( + NetHandle customer, + byte[] send, + ProgressReport sendStatus, + ProgressReport receiveStatus + ) + { + return ReadFromServerBase(HslCommunicationCode.Hsl_Protocol_User_Bytes, customer.get_CodeValue(), send, sendStatus, receiveStatus); + } + + /// + /// 需要发送的底层数据 + /// + /// 数据的指令头 + /// 用户的指令头 + /// 需要发送的底层数据 + /// 发送状态的进度报告,用于显示上传进度 + /// 接收状态的进度报告,用于显示下载进度 + /// + private OperateResultBytes ReadFromServerBase( + int headcode, + int customer, + byte[] send, + ProgressReport sendStatus, + ProgressReport receiveStatus) + { + OperateResultBytes result = new OperateResultBytes(); + + // 创建并连接套接字 + Socket socket=null; + boolWithSocket valueSocket=CreateSocketAndConnect(m_ipAddress, m_port,result); + if(!valueSocket.Result) + { + return result; + } + + socket = valueSocket.Socket; + + // 发送并检查数据是否发送完成 + if (!SendBaseAndCheckReceive(socket, headcode, customer, send, result, sendStatus,null)) + { + return result; + } + + // 接收头数据和内容数据 + + boolWith2Bytes value = ReceiveAndCheckBytes(socket, result, receiveStatus,null); + + if (!value.Result) + { + return result; + } + + CloseSocket(socket); + result.Content = value.Content2; + result.IsSuccess = true; + return result; + } + + +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Log/LogUtil.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Log/LogUtil.java new file mode 100644 index 0000000..bf11119 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Log/LogUtil.java @@ -0,0 +1,68 @@ +package com.example.HslCommunication.Log; + +import android.util.Log; + +/** + * Created by hsl20 on 2017/11/4. + * 一个扩展的日志工具,用来实现对记录日志的特殊处理,屏蔽操作 + */ + +public class LogUtil { + + public static final int VerBose = 1; + + public static final int Debug = 2; + + public static final int Info = 3; + + public static final int Warn = 4; + + public static final int Error = 5; + + public static final int Nothing = 6; + + public static int Level = VerBose; + + /* + 记录零碎的日志 + */ + public static void LogV(String tag, String msg) { + if (Level <= VerBose) Log.v(tag, msg); + } + + /* + 记录调试日志 + */ + public static void LogD(String tag, String msg) { + if (Level <= Debug) Log.d(tag, msg); + } + + /* + 记录信息日志 + */ + public static void LogI(String tag, String msg) { + if (Level <= Info) Log.i(tag, msg); + } + + /* + 记录警告日志 + */ + public static void LogW(String tag, String msg) { + if (Level <= Warn) Log.w(tag, msg); + } + + /* + 记录一般错误日志 + */ + public static void LogE(String tag, String msg) { + if (Level <= Error) Log.e(tag, msg); + } + + /* + 记录带信息异常的错误日志 + */ + public static void LogE(String tag, String msg, Exception ex) { + if (Level <= Error) Log.e(tag, msg, ex); + } + +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Profinet/PlcNetBase.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Profinet/PlcNetBase.java new file mode 100644 index 0000000..90a403e --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Profinet/PlcNetBase.java @@ -0,0 +1,72 @@ +package com.example.HslCommunication.Profinet; + +import com.example.HslCommunication.Core.Net.NetBase; + +/** + * Created by DATHLIN on 2017/11/3. + */ + +public abstract class PlcNetBase extends NetBase { + + + protected int m_PortRead = 1000; + protected int m_PortReadBackup = -1; + protected boolean m_IsPortNormal = true; + protected int m_PortWrite = 1001; + + + + /// + /// 获取访问的端口号 + /// + /// + protected int GetPort() + { + if (m_PortReadBackup <= 0) return m_PortRead; + return m_IsPortNormal ? m_PortRead : m_PortReadBackup; + } + /// + /// 更换端口号 + /// + protected void ChangePort() + { + m_IsPortNormal = !m_IsPortNormal; + } + + + public void setPortRead(int value) { + m_PortRead = value; + } + + + public int getPortRead() + { + return m_PortRead; + } + + + /// + /// 控制字节长度,超出选择截断,不够补零 + /// + /// 字节数据 + /// 最终需要的目标长度 + /// 处理后的数据 + protected byte[] ManageBytesLength(byte[] bytes, int length) + { + if (bytes == null) return null; + byte[] temp = new byte[length]; + if (length > bytes.length) + { + System.arraycopy(bytes, 0, temp, 0, bytes.length); + } + else + { + System.arraycopy(bytes, 0, temp, 0, length); + } + return temp; + } + + + + +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Profinet/SiemensPLCS.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Profinet/SiemensPLCS.java new file mode 100644 index 0000000..d5dd1b1 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Profinet/SiemensPLCS.java @@ -0,0 +1,11 @@ +package com.example.HslCommunication.Profinet; + +/** + * Created by DATHLIN on 2017/11/3. + */ + +public enum SiemensPLCS { + S1200, + S300, + Smart200, +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Profinet/SiemensTcpNet.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Profinet/SiemensTcpNet.java new file mode 100644 index 0000000..4ef28f6 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Profinet/SiemensTcpNet.java @@ -0,0 +1,780 @@ +package com.example.HslCommunication.Profinet; + +import com.example.HslCommunication.Core.Net.NetSupport; +import com.example.HslCommunication.Core.Types.OperateResult; +import com.example.HslCommunication.Core.Types.OperateResultBytes; +import com.example.HslCommunication.Core.Utilities.Utilities; +import com.example.HslCommunication.Core.Utilities.boolWithBytes; +import com.example.HslCommunication.Core.Utilities.boolWithSiemens; +import com.example.HslCommunication.Core.Utilities.boolWithSocket; + +import java.io.OutputStream; +import java.net.Socket; +import java.util.ArrayList; + +/** + * Created by DATHLIN on 2017/11/3. + */ + +public final class SiemensTcpNet extends PlcNetBase { + + /// + /// 实例化一个数据通信的对象,需要指定访问哪种Plc + /// + /// + public SiemensTcpNet(SiemensPLCS siemens) + { + m_PortRead = 102; + m_PortWrite = 102; + CurrentPlc = siemens; + + switch (siemens) + { + case S1200: plcHead1[18] = 1; break; + case S300: plcHead1[18] = 2; break; + case Smart200:plcHead1[18] = 1; break; + default: plcHead1[18] = 3; break; + } + } + + + /// + /// 可以手动设置PLC类型,用来测试原本不支持的数据访问功能 + /// + /// + public void SetPlcType(byte type) + { + plcHead1[18] = type; + } + + private String ipAddress=""; + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + + private boolWithBytes ReceiveBytesFromSocket(Socket socket) + { + boolWithBytes value =new boolWithBytes(); + try + { + // 先接收4个字节的数据 + byte[] head = NetSupport.ReadBytesFromSocket(socket, 4); + int receive = head[2] * 256 + head[3]; + value.Content = new byte[receive]; + System.arraycopy(head,0,value.Content,0, 4); + byte[] data = NetSupport.ReadBytesFromSocket(socket, receive - 4); + System.arraycopy(data,0,value.Content,4,data.length); + value.Result=true; + return value; + } + catch(Exception ex) + { + CloseSocket(socket); + return value; + } + } + + private boolean SendBytesToSocket(Socket socket, byte[] data) + { + try + { + if (data != null) + { + OutputStream outputStream = socket.getOutputStream(); + outputStream.write(data); + } + return true; + } + catch(Exception ex) + { + CloseSocket(socket); + return false; + } + } + + + private int CalculateAddressStarted(String address) + { + if (address.indexOf('.') < 0) + { + return Integer.parseInt(address) * 8; + } + else + { + String[] temp = address.split("\\."); + return Integer.parseInt(temp[0]) * 8 + Integer.parseInt(temp[1]); + } + } + + /// + /// 解析数据地址 + /// + /// 数据地址 + /// 类型 + /// 其实地址 + /// DB块地址 + /// 结果数据对象 + /// + private boolWithSiemens AnalysisAddress(String address, OperateResult result) + { + boolWithSiemens value = new boolWithSiemens(); + try + { + value.dbAddress = 0; + if (address.charAt(0) == 'I') + { + value.type = -127; + value.startAddress = CalculateAddressStarted(address.substring(1)); + } + else if (address.charAt(0) == 'Q') + { + value.type = -126; + value.startAddress = CalculateAddressStarted(address.substring(1)); + } + else if (address.charAt(0) == 'M') + { + value.type = -125; + value.startAddress = CalculateAddressStarted(address.substring(1)); + } + else if (address.charAt(0) == 'D' || address.substring(0, 2) == "DB") + { + value.type = -124; + String[] adds = address.split("\\."); + if (address.charAt(1) == 'B') + { + value.dbAddress = Short.parseShort(adds[0].substring(2)); + } + else + { + value.dbAddress = Short.parseShort(adds[0].substring(1)); + } + + value.startAddress = CalculateAddressStarted(address.substring(address.indexOf('.') + 1)); + } + else + { + result.Message = "不支持的数据类型"; + value.type = 0; + value.startAddress = 0; + value.dbAddress = 0; + return value; + } + } + catch (Exception ex) + { + result.Message = ex.getMessage(); + return value; + } + + value.Result=true; + return value; + } + + private boolean InitilizationConnect(Socket socket,OperateResult result) + { + // 发送初始化信息 + if(!SendBytesToSocket(socket,plcHead1)) + { + result.Message = "初始化信息发送失败"; + return false; + } + + if(!ReceiveBytesFromSocket(socket).Result) + { + result.Message = "初始化信息接收失败"; + return false; + } + + if(!SendBytesToSocket(socket,plcHead2)) + { + result.Message = "初始化信息发送失败"; + return false; + } + + if(!ReceiveBytesFromSocket(socket).Result) + { + result.Message = "初始化信息接收失败"; + return false; + } + + return true; + } + + + /// + /// 从PLC读取数据,地址格式为I100,Q100,DB20.100,M100,以字节为单位 + /// + /// 起始地址,格式为I100,M100,Q100,DB20.100 + /// 读取的数量,以字节为单位 + /// + public OperateResultBytes ReadFromPLC(String address, short count) + { + return ReadFromPLC(new String[] { address }, new short[] { count }); + } + + + /// + /// 一次性从PLC获取所有的数据,按照先后顺序返回一个统一的Buffer,需要按照顺序处理,两个数组长度必须一致 + /// + /// 起始地址数组 + /// 数据长度数组 + /// + public OperateResultBytes ReadFromPLC(String[] address, short[] count) + { + OperateResultBytes result = new OperateResultBytes(); + + if (address == null) + { + result.Message = "地址不能为空"; + return result; + } + + + if (count == null) + { + result.Message = "数量不能为空"; + return result; + } + if (address.length != count.length) { + result.Message = "两个参数的个数不统一"; + return result; + } + + Socket socket; + boolWithSocket value = CreateSocketAndConnect(ipAddress,getPortRead(), result); + if (!value.Result) + { + ChangePort(); + return result; + } + + socket = value.Socket; + if (!InitilizationConnect(socket, result)) + { + return result; + } + + + // 分批次进行读取,计算总批次 + int times = address.length / 255; + if (address.length % 255 > 0) + { + times++; + } + + // 缓存所有批次的结果 + ArrayList arrays_bytes = new ArrayList(); + + for (int jj = 0; jj < times; jj++) + { + // 计算本批次需要读取的数据 + int startIndex = jj * 255; + int readCount = address.length - startIndex; + if (readCount > 255) + { + readCount = 255; + } + + byte[] _PLCCommand = new byte[19 + readCount * 12]; + // 报文头 + _PLCCommand[0] = 0x03; + _PLCCommand[1] = 0x00; + // 长度 + _PLCCommand[2] = (byte)(_PLCCommand.length / 256); + _PLCCommand[3] = (byte)(_PLCCommand.length % 256); + // 固定 + _PLCCommand[4] = 0x02; + _PLCCommand[5] = -16; + _PLCCommand[6] = -128; + _PLCCommand[7] = 0x32; + // 命令:发 + _PLCCommand[8] = 0x01; + // 标识序列号 + _PLCCommand[9] = 0x00; + _PLCCommand[10] = 0x00; + _PLCCommand[11] = 0x00; + _PLCCommand[12] = 0x01; + // 命令数据总长度 + _PLCCommand[13] = (byte)((_PLCCommand.length - 17) / 256); + _PLCCommand[14] = (byte)((_PLCCommand.length - 17) % 256); + + _PLCCommand[15] = 0x00; + _PLCCommand[16] = 0x00; + + // 命令起始符 + _PLCCommand[17] = 0x04; + // 读取数据块个数 + _PLCCommand[18] = (byte)readCount; + + int receiveCount = 0; + for (int ii = 0; ii < readCount; ii++) + { + receiveCount += count[ii + 255 * jj]; + + boolWithSiemens siemens = AnalysisAddress(address[ii + 255 * jj], result); + // 填充数据 + if (!siemens.Result) + { + CloseSocket(socket); + return result; + } + + // 读取地址的前缀 + _PLCCommand[19 + ii * 12] = 0x12; + _PLCCommand[20 + ii * 12] = 0x0A; + _PLCCommand[21 + ii * 12] = 0x10; + _PLCCommand[22 + ii * 12] = 0x02; + // 访问数据的个数 + _PLCCommand[23 + ii * 12] = (byte)(count[ii + 255 * jj] / 256); + _PLCCommand[24 + ii * 12] = (byte)(count[ii + 255 * jj] % 256); + // DB块编号,如果访问的是DB块的话 + _PLCCommand[25 + ii * 12] = (byte)(siemens.dbAddress / 256); + _PLCCommand[26 + ii * 12] = (byte)(siemens.dbAddress % 256); + // 访问数据类型 + _PLCCommand[27 + ii * 12] = siemens.type; + // 偏移位置 + _PLCCommand[28 + ii * 12] = (byte)(siemens.startAddress / 256 / 256); + _PLCCommand[29 + ii * 12] = (byte)(siemens.startAddress / 256); + _PLCCommand[30 + ii * 12] = (byte)(siemens.startAddress % 256); + } + + + if (!SendBytesToSocket(socket, _PLCCommand)) + { + result.Message = "发送读取信息失败"; + return result; + } + + boolWithBytes content=ReceiveBytesFromSocket(socket); + if (!content.Result) + { + result.Message = "接收信息失败"; + return result; + } + + if (content.Content.length != receiveCount + readCount * 4 + 21) + { + CloseSocket(socket); + result.Message = "数据长度校验失败"; + result.Content = content.Content; + return result; + } + + // 分次读取成功 + byte[] buffer = new byte[receiveCount]; + int kk = 21; + int ll = 0; + for (int ii = 0; ii < readCount; ii++) + { + // 将数据挪回正确的地方 + System.arraycopy(content, kk + 4, buffer, ll, count[ii + 255 * jj]); + kk += count[ii + 255 * jj] + 4; + ll += count[ii + 255 * jj]; + } + arrays_bytes.add(buffer); + } + + + if (arrays_bytes.size() == 1) + { + result.Content = arrays_bytes.get(0); + } + else + { + int length = 0; + int offset = 0; + + // 获取长度并生成缓冲数据 + + for(int ii=0;ii + /// 将数据写入到PLC数据,地址格式为I100,Q100,DB20.100,M100,以字节为单位 + /// + /// 起始地址,格式为I100,M100,Q100,DB20.100 + /// 写入的数据,长度根据data的长度来指示 + /// + public OperateResult WriteIntoPLC(String address, byte[] data) + { + OperateResult result = new OperateResult(); + + + Socket socket; + boolWithSocket value = CreateSocketAndConnect(ipAddress,getPortRead(), result); + if (!value.Result) + { + ChangePort(); + return result; + } + + socket = value.Socket; + if (!InitilizationConnect(socket, result)) + { + return result; + } + + + if (data == null) data = new byte[0]; + + boolWithSiemens siemens = AnalysisAddress(address, result); + // 填充数据 + if (!siemens.Result) + { + CloseSocket(socket); + return result; + } + + + byte[] _PLCCommand = new byte[35 + data.length]; + _PLCCommand[0] = 0x03; + _PLCCommand[1] = 0x00; + // 长度 + _PLCCommand[2] = (byte)((35 + data.length) / 256); + _PLCCommand[3] = (byte)((35 + data.length) % 256); + // 固定 + _PLCCommand[4] = 0x02; + _PLCCommand[5] = -16; + _PLCCommand[6] = -128; + _PLCCommand[7] = 0x32; + // 命令 发 + _PLCCommand[8] = 0x01; + // 标识序列号 + _PLCCommand[9] = 0x00; + _PLCCommand[10] = 0x00; + _PLCCommand[11] = 0x00; + _PLCCommand[12] = 0x01; + // 固定 + _PLCCommand[13] = 0x00; + _PLCCommand[14] = 0x0E; + // 写入长度+4 + _PLCCommand[15] = (byte)((4 + data.length) / 256); + _PLCCommand[16] = (byte)((4 + data.length) % 256); + // 命令起始符 + _PLCCommand[17] = 0x05; + // 写入数据块个数 + _PLCCommand[18] = 0x01; + // 固定,返回数据长度 + _PLCCommand[19] = 0x12; + _PLCCommand[20] = 0x0A; + _PLCCommand[21] = 0x10; + // 写入方式,1是按位,2是按字 + _PLCCommand[22] = 0x02; + // 写入数据的个数 + _PLCCommand[23] = (byte)(data.length / 256); + _PLCCommand[24] = (byte)(data.length % 256); + // DB块编号,如果访问的是DB块的话 + _PLCCommand[25] = (byte)(siemens.dbAddress / 256); + _PLCCommand[26] = (byte)(siemens.dbAddress % 256); + // 写入数据的类型 + _PLCCommand[27] = siemens.type; + // 偏移位置 + _PLCCommand[28] = (byte)(siemens.startAddress / 256 / 256);; + _PLCCommand[29] = (byte)(siemens.startAddress / 256); + _PLCCommand[30] = (byte)(siemens.startAddress % 256); + // 按字写入 + _PLCCommand[31] = 0x00; + _PLCCommand[32] = 0x04; + // 按位计算的长度 + _PLCCommand[33] = (byte)(data.length * 8 / 256); + _PLCCommand[34] = (byte)(data.length * 8 % 256); + + System.arraycopy(data,0,_PLCCommand,35,data.length); + + if(!SendBytesToSocket(socket,_PLCCommand)) + { + result.Message = "发送写入信息失败"; + return result; + } + + boolWithBytes value2=ReceiveBytesFromSocket(socket); + if (!value2.Result) + { + result.Message = "接收信息失败"; + return result; + } + + if (value2.Content[value2.Content.length - 1] != 0xFF) + { + // 写入异常 + CloseSocket(socket); + result.Message = "写入数据异常"; + return result; + } + + CloseSocket(socket); + result.IsSuccess = true; + return result; + } + + + /// + /// 写入PLC的一个位,例如"M100.6","I100.7","Q100.0","DB20.100.0",如果只写了"M100"默认为"M100.0 + /// + /// + /// + /// + public OperateResult WriteIntoPLC(String address, boolean data) + { + OperateResult result = new OperateResult(); + + Socket socket; + boolWithSocket value = CreateSocketAndConnect(getIpAddress(),m_PortWrite, result); + if (!value.Result) + { + ChangePort(); + return result; + } + + socket = value.Socket; + if (!InitilizationConnect(socket, result)) + { + return result; + } + + + + byte[] buffer = new byte[1]; + buffer[0] = data ? (byte)0x01 : (byte)0x00; + + boolWithSiemens siemens = AnalysisAddress(address, result); + // 填充数据 + if (!siemens.Result) + { + CloseSocket(socket); + return result; + } + + + + byte[] _PLCCommand = new byte[35 + buffer.length]; + _PLCCommand[0] = 0x03; + _PLCCommand[1] = 0x00; + // 长度 + _PLCCommand[2] = (byte)((35 + buffer.length) / 256); + _PLCCommand[3] = (byte)((35 + buffer.length) % 256); + // 固定 + _PLCCommand[4] = 0x02; + _PLCCommand[5] = -16; + _PLCCommand[6] = -128; + _PLCCommand[7] = 0x32; + // 命令 发 + _PLCCommand[8] = 0x01; + // 标识序列号 + _PLCCommand[9] = 0x00; + _PLCCommand[10] = 0x00; + _PLCCommand[11] = 0x00; + _PLCCommand[12] = 0x01; + // 固定 + _PLCCommand[13] = 0x00; + _PLCCommand[14] = 0x0E; + // 写入长度+4 + _PLCCommand[15] = (byte)((4 + buffer.length) / 256); + _PLCCommand[16] = (byte)((4 + buffer.length) % 256); + // 命令起始符 + _PLCCommand[17] = 0x05; + // 写入数据块个数 + _PLCCommand[18] = 0x01; + _PLCCommand[19] = 0x12; + _PLCCommand[20] = 0x0A; + _PLCCommand[21] = 0x10; + // 写入方式,1是按位,2是按字 + _PLCCommand[22] = 0x01; + // 写入数据的个数 + _PLCCommand[23] = (byte)(buffer.length / 256); + _PLCCommand[24] = (byte)(buffer.length % 256); + // DB块编号,如果访问的是DB块的话 + _PLCCommand[25] = (byte)(siemens.dbAddress / 256); + _PLCCommand[26] = (byte)(siemens.dbAddress % 256); + // 写入数据的类型 + _PLCCommand[27] = siemens.type; + // 偏移位置 + _PLCCommand[28] = (byte)(siemens.startAddress / 256 / 256); + _PLCCommand[29] = (byte)(siemens.startAddress / 256); + _PLCCommand[30] = (byte)(siemens.startAddress % 256); + // 按位写入 + _PLCCommand[31] = 0x00; + _PLCCommand[32] = 0x03; + // 按位计算的长度 + _PLCCommand[33] = (byte)(buffer.length / 256); + _PLCCommand[34] = (byte)(buffer.length % 256); + + System.arraycopy(buffer,0,_PLCCommand,35,buffer.length); + + if(!SendBytesToSocket(socket,_PLCCommand)) + { + result.Message = "发送写入信息失败"; + return result; + } + + boolWithBytes value2=ReceiveBytesFromSocket(socket); + if (!value2.Result) + { + result.Message = "接收信息失败"; + return result; + } + + if (value2.Content[value2.Content.length - 1] != 0xFF) + { + // 写入异常 + CloseSocket(socket); + result.Message = "写入数据异常"; + return result; + } + + CloseSocket(socket); + result.IsSuccess = true; + return result; + } + + /// + /// 从返回的西门子数组中获取short数组数据,已经内置高地位转换 + /// + /// + /// + public short[] GetArrayFromBytes(byte[] bytes) + { + short[] temp = new short[bytes.length / 2]; + for (int i = 0; i < temp.length; i++) + { + byte[] buffer = new byte[2]; + buffer[0] = bytes[i * 2 + 1]; + buffer[1] = bytes[i * 2]; + temp[i] = Utilities.byte2Short(buffer, 0); + } + return temp; + } + + /// + /// 从返回的西门子数组中获取int数组数据,已经内置高地位转换 + /// + /// + /// + public int[] GetIntArrayFromBytes(byte[] bytes) + { + int[] temp = new int[bytes.length / 4]; + for (int i = 0; i < temp.length; i++) + { + byte[] buffer = new byte[4]; + buffer[0] = bytes[i * 4 + 0]; + buffer[1] = bytes[i * 4 + 1]; + buffer[2] = bytes[i * 4 + 2]; + buffer[3] = bytes[i * 4 + 3]; + temp[i] = Utilities.bytes2Int(buffer); + } + return temp; + } + + /// + /// 根据索引位转换获取short数据 + /// + /// + /// + /// + public short GetShortFromBytes(byte[] content, int index) + { + byte[] buffer = new byte[2]; + buffer[0] = content[index + 0]; + buffer[1] = content[index + 1]; + return Utilities.byte2Short(buffer,0); + } + + + /// + /// 根据索引位转换获取int数据 + /// + /// + /// + /// + public int GetIntFromBytes(byte[] content, int index) + { + byte[] buffer = new byte[4]; + buffer[0] = content[index + 0]; + buffer[1] = content[index + 1]; + buffer[2] = content[index + 2]; + buffer[3] = content[index + 3]; + return Utilities.bytes2Int(buffer); + } + + private byte[] plcHead1 = + { + 0x03, // 报文头 + 0x00, + 0x00, // 数据长度 + 0x16, + 0x11, + -32, + 0x00, + 0x00, + 0x00, + 0x01, + 0x00, + -63, + 0x02, + 0x10, + 0x00, + -62, + 0x02, + 0x03, + 0x01, // 指示cpu + -64, + 0x01, + 0x0A + }; + private byte[] plcHead2 = + { + 0x03, + 0x00, + 0x00, + 0x19, + 0x02, + -16, + -128, + 0x32, + 0x01, + 0x00, + 0x00, + -52, + -63, + 0x00, + 0x08, + 0x00, + 0x00, + -16, + 0x00, + 0x00, + 0x01, + 0x00, + 0x01, + 0x03, + -64 + }; + + private SiemensPLCS CurrentPlc = SiemensPLCS.S1200; + + +} diff --git a/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Resources/StringResources.java b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Resources/StringResources.java new file mode 100644 index 0000000..f005a31 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/HslCommunication/Resources/StringResources.java @@ -0,0 +1,95 @@ +package com.example.HslCommunication.Resources; + +/** + * Created by DATHLIN on 2017/11/2. + */ + +public class StringResources { + + + /*********************************************************************************** + * + * 一般的错误信息 + * + ************************************************************************************/ + + + public static final String ConnectedFailed = "连接失败"; + public static final String UnknownError = "未知错误"; + public static final String ErrorCode = "错误代号"; + public static final String TextDescription = "文本描述"; + public static final String ExceptionMessage = "错误信息:"; + public static final String ExceptionStackTrace = "错误堆栈:"; + public static final String ExceptopnTargetSite = "错误方法:"; + public static final String ExceprionCustomer = "用户自定义方法出错:"; + + + + /*********************************************************************************** + * + * 系统相关的错误信息 + * + ************************************************************************************/ + + public static final String SystemInstallOperater = "安装新系统:IP为"; + public static final String SystemUpdateOperater = "更新新系统:IP为"; + + + /*********************************************************************************** + * + * 套接字相关的信息描述 + * + ************************************************************************************/ + + public static final String SocketIOException = "套接字传送数据异常:"; + public static final String SocketSendException = "同步数据发送异常:"; + public static final String SocketHeadReceiveException = "指令头接收异常:"; + public static final String SocketContentReceiveException = "内容数据接收异常:"; + public static final String SocketContentRemoteReceiveException = "对方内容数据接收异常:"; + public static final String SocketAcceptCallbackException = "异步接受传入的连接尝试"; + public static final String SocketReAcceptCallbackException = "重新异步接受传入的连接尝试"; + public static final String SocketSendAsyncException = "异步数据发送出错:"; + public static final String SocketEndSendException = "异步数据结束挂起发送出错"; + public static final String SocketReceiveException = "异步数据发送出错:"; + public static final String SocketEndReceiveException = "异步数据结束接收指令头出错"; + public static final String SocketRemoteCloseException = "远程主机强迫关闭了一个现有的连接"; + + + /*********************************************************************************** + * + * 文件相关的信息 + * + ************************************************************************************/ + + + public static final String FileDownloadSuccess = "文件下载成功"; + public static final String FileDownloadFailed = "文件下载异常"; + public static final String FileUploadFailed = "文件上传异常"; + public static final String FileUploadSuccess = "文件上传成功"; + public static final String FileDeleteFailed = "文件删除异常"; + public static final String FileDeleteSuccess = "文件删除成功"; + public static final String FileReceiveFailed = "确认文件接收异常"; + public static final String FileNotExist = "文件不存在"; + public static final String FileSaveFailed = "文件存储失败"; + public static final String FileLoadFailed = "文件加载失败"; + public static final String FileSendClientFailed = "文件发送的时候发生了异常"; + public static final String FileWriteToNetFailed = "文件写入网络异常"; + public static final String FileReadFromNetFailed = "从网络读取文件异常"; + + /*********************************************************************************** + * + * 服务器的引擎相关数据 + * + ************************************************************************************/ + + public static final String TokenCheckFailed = "接收验证令牌不一致"; + public static final String TokenCheckTimeout = "接收验证超时:"; + public static final String NetClientAliasFailed = "客户端的别名接收失败:"; + public static final String NetEngineStart = "启动引擎"; + public static final String NetEngineClose = "关闭引擎"; + public static final String NetClientOnline = "上线"; + public static final String NetClientOffline = "下线"; + public static final String NetClientBreak = "异常掉线"; + public static final String NetClientFull = "服务器承载上限,收到超出的请求连接。"; + public static final String NetClientLoginFailed = "客户端登录中错误:"; +} diff --git a/AndroidTemplate/app/src/main/java/com/example/UserSoftwareAndroidTemplate/CommonHeadCode/SimplifyHeadCode.java b/AndroidTemplate/app/src/main/java/com/example/UserSoftwareAndroidTemplate/CommonHeadCode/SimplifyHeadCode.java new file mode 100644 index 0000000..d348e3a --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/UserSoftwareAndroidTemplate/CommonHeadCode/SimplifyHeadCode.java @@ -0,0 +1,60 @@ +package com.example.UserSoftwareAndroidTemplate.CommonHeadCode; + +import com.example.HslCommunication.Core.Types.NetHandle; + +/** + * Created by hsl20 on 2017/11/5. + */ + +public class SimplifyHeadCode { + + + public static NetHandle 维护检查 = new NetHandle(1, 1, 1); + public static NetHandle 更新检查 = new NetHandle(1, 1, 2); + public static NetHandle 参数下载 = new NetHandle(1, 1, 3); + public static NetHandle 账户检查 = new NetHandle(1, 1, 4); + public static NetHandle 密码修改 = new NetHandle(1, 1, 5); + public static NetHandle 更细账户 = new NetHandle(1, 1, 6); + public static NetHandle 获取账户 = new NetHandle(1, 1, 7); + public static NetHandle 更新公告 = new NetHandle(1, 1, 8); + public static NetHandle 注册账号 = new NetHandle(1, 1, 9); + public static NetHandle 更新版本 = new NetHandle(1, 1, 10); + public static NetHandle 请求文件 = new NetHandle(1, 1, 11); + public static NetHandle 意见反馈 = new NetHandle(1, 1, 12); + public static NetHandle 群发消息 = new NetHandle(1, 1, 13); + public static NetHandle 异常消息 = new NetHandle(1, 1, 14); + public static NetHandle 性能计数 = new NetHandle(1, 1, 15); + public static NetHandle 上传头像MD5 = new NetHandle(1, 1, 16); + public static NetHandle 请求分厂 = new NetHandle(1, 1, 17); + public static NetHandle 上传分厂 = new NetHandle(1, 1, 18); + public static NetHandle 请求信任客户端 = new NetHandle(1, 1, 19); + public static NetHandle 上传信任客户端 = new NetHandle(1, 1, 20); + public static NetHandle 请求一般配置 = new NetHandle(1, 1, 21); + public static NetHandle 上传一般配置 = new NetHandle(1, 1, 22); + public static NetHandle 请求角色配置 = new NetHandle(1, 1, 23); + public static NetHandle 上传角色配置 = new NetHandle(1, 1, 24); + public static NetHandle 检查角色权限 = new NetHandle(1, 1, 25); + + + + + + public static NetHandle 网络日志查看 = new NetHandle(1, 2, 1);//1.2.开头的是日志请求和清空 + public static NetHandle 网络日志清空 = new NetHandle(1, 2, 2); + public static NetHandle 同步日志查看 = new NetHandle(1, 2, 3); + public static NetHandle 同步日志清空 = new NetHandle(1, 2, 4); + public static NetHandle 更新日志查看 = new NetHandle(1, 2, 5); + public static NetHandle 更新日志清空 = new NetHandle(1, 2, 6); + public static NetHandle 运行日志查看 = new NetHandle(1, 2, 7); + public static NetHandle 运行日志清空 = new NetHandle(1, 2, 8); + public static NetHandle 文件日志查看 = new NetHandle(1, 2, 9); + public static NetHandle 文件日志清空 = new NetHandle(1, 2, 10); + public static NetHandle 反馈日志查看 = new NetHandle(1, 2, 11); + public static NetHandle 反馈日志清空 = new NetHandle(1, 2, 12); + public static NetHandle UDP日志查看 = new NetHandle(1, 2, 13); + public static NetHandle UDP日志清空 = new NetHandle(1, 2, 14); + public static NetHandle 客户端日志查看 = new NetHandle(1, 2, 15); + public static NetHandle 客户端日志清空 = new NetHandle(1, 2, 16); + public static NetHandle 头像日志查看 = new NetHandle(1, 2, 17); + public static NetHandle 头像日志清空 = new NetHandle(1, 2, 18); +} diff --git a/AndroidTemplate/app/src/main/java/com/example/UserSoftwareAndroidTemplate/LoginSupport/SplashActivity.java b/AndroidTemplate/app/src/main/java/com/example/UserSoftwareAndroidTemplate/LoginSupport/SplashActivity.java new file mode 100644 index 0000000..db4f8d1 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/UserSoftwareAndroidTemplate/LoginSupport/SplashActivity.java @@ -0,0 +1,136 @@ +package com.example.UserSoftwareAndroidTemplate.LoginSupport; + +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.support.design.widget.FloatingActionButton; +import android.support.design.widget.Snackbar; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import com.example.HslCommunication.BasicFramework.SystemVersion; +import com.example.HslCommunication.Core.Types.NetHandle; +import com.example.HslCommunication.Core.Types.OperateResultString; +import com.example.UserSoftwareAndroidTemplate.CommonHeadCode.SimplifyHeadCode; +import com.example.UserSoftwareAndroidTemplate.MainActivity; +import com.example.UserSoftwareAndroidTemplate.R; +import com.example.UserSoftwareAndroidTemplate.UserClient; + + +public class SplashActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_splash); + + TextView mVersionNameText = (TextView) findViewById(R.id.TextVersionInfo); + mVersionNameText.setText("Version: " + UserClient.CurrentVersion.toString()); + + new AsyncTask() { + + + @Override + protected Integer doInBackground(Void... voids) { + int result; + long startTime = System.currentTimeMillis(); + result = loadingCache(); + long loadingTime = System.currentTimeMillis() - startTime; + if (loadingTime < SHOW_TIME_MIN) { + try { + Thread.sleep(SHOW_TIME_MIN - loadingTime); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + return result; + } + + @Override + protected void onPostExecute(Integer result) { + if (result > 0) { + Intent intent = new Intent(SplashActivity.this, MainActivity.class); + //intent.setClassName(SplashActivity.this, getString(R.string.)); + startActivity(intent); + finish(); + //两个参数分别表示进入的动画,退出的动画 + overridePendingTransition(R.anim.fade_in, R.anim.fade_out); + } + } + + ; + }.execute(new Void[]{}); + + } + + private static final int SHOW_TIME_MIN = 3000; + private static final int FAILURE = 0; // 失败 + private static final int SUCCESS = 1; // 成功 + private static final int OFFLINE = 2; // 如果支持离线阅读,进入离线模式 + + + private Handler handler=new Handler(){ + /**重写handleMessage方法*/ + @Override + public void handleMessage(Message msg) { + if (msg.arg1 == 1) { + Toast.makeText(SplashActivity.this, msg.obj.toString(), Toast.LENGTH_SHORT).show(); + } + } + }; + + + private void MessageShow(String message) + { + Message msg = new Message(); + msg.arg1=1; + msg.obj = message; + handler.sendMessage(msg); + } + + + private int loadingCache() { + + // 第一步请求维护状态 + OperateResultString result=UserClient.Client.ReadFromServer(SimplifyHeadCode.维护检查,"",null,null); + if(!result.IsSuccess){ + MessageShow(result.ToMessageShowString()); + return FAILURE; + } + + if(!result.Content.equals("1")) { + MessageShow(result.Content.substring(1)); + return FAILURE; + } + + + // 第二步检查账户 + + + + + + + // 第三步检查版本 + result=UserClient.Client.ReadFromServer(SimplifyHeadCode.维护检查,"",null,null); + if(!result.IsSuccess){ + MessageShow(result.ToMessageShowString()); + return FAILURE; + } + + SystemVersion sv=new SystemVersion(result.Content); + if(!UserClient.CurrentVersion.IsSameVersion(sv)) return FAILURE; + + + // 下载服务器数据 + + + return SUCCESS; + } + +} diff --git a/AndroidTemplate/app/src/main/java/com/example/UserSoftwareAndroidTemplate/MainActivity.java b/AndroidTemplate/app/src/main/java/com/example/UserSoftwareAndroidTemplate/MainActivity.java new file mode 100644 index 0000000..afd1b10 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/UserSoftwareAndroidTemplate/MainActivity.java @@ -0,0 +1,83 @@ +package com.example.UserSoftwareAndroidTemplate; + +import android.os.Handler; +import android.os.Message; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.text.method.ScrollingMovementMethod; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import com.example.HslCommunication.Core.Types.NetHandle; +import com.example.HslCommunication.Core.Types.OperateResultString; +import com.example.HslCommunication.Enthernet.NetSimplifyClient; + +import java.util.UUID; + +public class MainActivity extends AppCompatActivity { + + public MainActivity() + { + + } + + + + + + private Handler handler=new Handler(){ + /**重写handleMessage方法*/ + @Override + public void handleMessage(Message msg) { + if (msg.arg1 == 1) { + + // 说明是一个网络的请求访问 + OperateResultString result = (OperateResultString) msg.obj; + if (result.IsSuccess) { + TextView textView = (TextView) findViewById(R.id.textViewMain); + textView.setText(result.Content); + } else { + Toast.makeText(MainActivity.this, result.ToMessageShowString(), Toast.LENGTH_LONG).show(); + } + } + } + }; + + + /** + * 网络操作相关的子线程 + */ + Runnable networkTask = new Runnable() { + + @Override + public void run() { + // 在这里进行网络请求相关操作 + Message msg = new Message(); + OperateResultString result = UserClient.Client.ReadFromServer(new NetHandle(1,2, 15),"",null,null); + msg.arg1=1; + msg.obj = result; + handler.sendMessage(msg); + } + }; + + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Button button1 = (Button) findViewById(R.id.button); + button1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + new Thread(networkTask).start(); + }}); + + TextView textView = (TextView) findViewById(R.id.textViewMain); + textView.setMovementMethod(new ScrollingMovementMethod()); + } +} diff --git a/AndroidTemplate/app/src/main/java/com/example/UserSoftwareAndroidTemplate/UserClient.java b/AndroidTemplate/app/src/main/java/com/example/UserSoftwareAndroidTemplate/UserClient.java new file mode 100644 index 0000000..fc6cf84 --- /dev/null +++ b/AndroidTemplate/app/src/main/java/com/example/UserSoftwareAndroidTemplate/UserClient.java @@ -0,0 +1,33 @@ +package com.example.UserSoftwareAndroidTemplate; + +import com.example.HslCommunication.BasicFramework.SystemVersion; +import com.example.HslCommunication.Enthernet.NetSimplifyClient; + +import java.util.UUID; + +/** + * Created by hsl20 on 2017/11/4. + */ + +public class UserClient { + + + public static SystemVersion CurrentVersion= new SystemVersion("1.0.0.171026"); + + + + public static String ServerIp="117.48.203.204"; + public static int PortSecondary=14568; + public static UUID Token=UUID.fromString("1275BB9A-14B2-4A96-9673-B0AF0463D474"); + + + + + + + + + + public static NetSimplifyClient Client=new NetSimplifyClient(ServerIp,PortSecondary,Token); + +} diff --git a/AndroidTemplate/app/src/main/res/anim/fade_in.xml b/AndroidTemplate/app/src/main/res/anim/fade_in.xml new file mode 100644 index 0000000..3a7854d --- /dev/null +++ b/AndroidTemplate/app/src/main/res/anim/fade_in.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/AndroidTemplate/app/src/main/res/anim/fade_out.xml b/AndroidTemplate/app/src/main/res/anim/fade_out.xml new file mode 100644 index 0000000..55885fa --- /dev/null +++ b/AndroidTemplate/app/src/main/res/anim/fade_out.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/AndroidTemplate/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/AndroidTemplate/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..c7bd21d --- /dev/null +++ b/AndroidTemplate/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/AndroidTemplate/app/src/main/res/drawable/ic_launcher_background.xml b/AndroidTemplate/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..d5fccc5 --- /dev/null +++ b/AndroidTemplate/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AndroidTemplate/app/src/main/res/layout/activity_main.xml b/AndroidTemplate/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..1d5560c --- /dev/null +++ b/AndroidTemplate/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,26 @@ + + + + + +