├── .gitignore
├── .idea
├── .name
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── AndroidSocketClient.iml
├── README.md
├── app
├── .gitignore
├── app.iml
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── vilyever
│ │ └── androidsocketclient
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── vilyever
│ │ └── androidsocketclient
│ │ ├── App.java
│ │ ├── FileUtil.java
│ │ ├── MainActivity.java
│ │ ├── TestClient.java
│ │ └── TestServer.java
│ └── res
│ ├── layout
│ └── activity_main.xml
│ ├── menu
│ └── menu_main.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── socketclient
├── .gitignore
├── build.gradle
├── build_library_ext.gradle
├── proguard-rules.pro
├── socketclient.iml
└── src
├── androidTest
└── java
│ └── com
│ └── vilyever
│ └── socketclient
│ └── ApplicationTest.java
└── main
├── AndroidManifest.xml
├── java
└── com
│ └── vilyever
│ └── socketclient
│ ├── SocketClient.java
│ ├── helper
│ ├── SocketClientAddress.java
│ ├── SocketClientDelegate.java
│ ├── SocketClientReceivingDelegate.java
│ ├── SocketClientSendingDelegate.java
│ ├── SocketConfigure.java
│ ├── SocketHeartBeatHelper.java
│ ├── SocketInputReader.java
│ ├── SocketPacket.java
│ ├── SocketPacketHelper.java
│ └── SocketResponsePacket.java
│ ├── server
│ ├── SocketServer.java
│ ├── SocketServerClient.java
│ └── SocketServerDelegate.java
│ └── util
│ ├── BytesWrapper.java
│ ├── CharsetUtil.java
│ ├── IPUtil.java
│ └── StringValidation.java
└── res
└── values
└── strings.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Android Studio
2 | *.iml
3 | .idea
4 | #.idea/workspace.xml - remove # and delete .idea if it better suit your needs.
5 | .gradle
6 | build/
7 | /local.properties
8 | /captures
9 |
10 | # OSX files
11 | .DS_Store
12 |
13 | # Windows thumbnail db
14 | Thumbs.db
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | AndroidSocketClient
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
26 |
27 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | Android Lint
52 |
53 |
54 | Internationalization issues
55 |
56 |
57 | Internationalization issuesJava
58 |
59 |
60 | Java
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | 1.7
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/AndroidSocketClient.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AndroidSocketClient
2 | socket client server简易封装
3 |
4 | ## Import
5 | [JitPack](https://jitpack.io/)
6 |
7 | Add it in your project's build.gradle at the end of repositories:
8 |
9 | ```gradle
10 | repositories {
11 | // ...
12 | maven { url "https://jitpack.io" }
13 | }
14 | ```
15 |
16 | Step 2. Add the dependency in the form
17 |
18 | ```gradle
19 | dependencies {
20 | compile 'com.github.vilyever:AndroidSocketClient:3.0.3'
21 | }
22 | ```
23 |
24 | ## Updates
25 | * 3.0.3
26 |
27 | 提升readByLength按长度读取的速度 [issue #26](/../../issues/26)
28 |
29 | * 3.0.2
30 |
31 | 修复初次连接失败时,因CountDownTimer导致崩溃的问题 [issue #24](/../../issues/24)
32 |
33 | * 3.0.1
34 |
35 | 修复包头验证bug,by zzdwuliang
36 |
37 | 增加地址检测的详细log
38 |
39 |
40 | * 3.0.0
41 |
42 | 支持ReadToData和ReadToLength自动读取以下两种结构
43 |
44 | 常见包结构1:【包头(可选)】【正文】【包尾】
45 |
46 | 常见包结构2:【包头(可选)】【余下包长度(正文加包尾长度)(此部分也可做包头)(此部分长度固定)】【正文】【包尾(可选)】
47 |
48 | ## Usage
49 | ### app模块下包含简单的使用demo
50 | ### 请一定设置读取策略socketClient.getSocketPacketHelper().setReadStrategy();
51 |
52 | ### 远程端连接信息配置
53 | ```java
54 | socketClient.getAddress().setRemoteIP(IPUtil.getLocalIPAddress(true)); // 远程端IP地址
55 | socketClient.getAddress().setRemotePort("21998"); // 远程端端口号
56 | socketClient.getAddress().setConnectionTimeout(15 * 1000); // 连接超时时长,单位毫秒
57 | ```
58 |
59 | ### 默认String编码配置
60 | ```java
61 | /**
62 | * 设置自动转换String类型到byte[]类型的编码
63 | * 如未设置(默认为null),将不能使用{@link SocketClient#sendString(String)}发送消息
64 | * 如设置为非null(如UTF-8),在接受消息时会自动尝试在接收线程(非主线程)将接收的byte[]数据依照编码转换为String,在{@link SocketResponsePacket#getMessage()}读取
65 | */
66 | socketClient.setCharsetName(CharsetUtil.UTF_8); // 设置编码为UTF-8
67 | ```
68 |
69 | ### 固定心跳包配置
70 | ```java
71 | /**
72 | * 设置自动发送的心跳包信息
73 | */
74 | socketClient.getHeartBeatHelper().setDefaultSendData(CharsetUtil.stringToData("HeartBeat", CharsetUtil.UTF_8));
75 |
76 | /**
77 | * 设置远程端发送到本地的心跳包信息内容,用于判断接收到的数据包是否是心跳包
78 | * 通过{@link SocketResponsePacket#isHeartBeat()} 查看数据包是否是心跳包
79 | */
80 | socketClient.getHeartBeatHelper().setDefaultReceiveData(CharsetUtil.stringToData("HeartBeat", CharsetUtil.UTF_8));
81 |
82 | socketClient.getHeartBeatHelper().setHeartBeatInterval(10 * 1000); // 设置自动发送心跳包的间隔时长,单位毫秒
83 | socketClient.getHeartBeatHelper().setSendHeartBeatEnabled(true); // 设置允许自动发送心跳包,此值默认为false
84 | ```
85 |
86 | ### 动态变化心跳包配置
87 | ```java
88 | /**
89 | * 设置自动发送的心跳包信息
90 | * 此信息动态生成
91 | *
92 | * 每次发送心跳包时自动调用
93 | */
94 | socketClient.getHeartBeatHelper().setSendDataBuilder(new SocketHeartBeatHelper.SendDataBuilder() {
95 | @Override
96 | public byte[] obtainSendHeartBeatData(SocketHeartBeatHelper helper) {
97 | /**
98 | * 使用当前日期作为心跳包
99 | */
100 | byte[] heartBeatPrefix = new byte[]{0x1F, 0x1F};
101 | byte[] heartBeatSuffix = new byte[]{0x1F, 0x1F};
102 |
103 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
104 | byte[] heartBeatInfo = CharsetUtil.stringToData(sdf.format(new Date()), CharsetUtil.UTF_8);
105 |
106 | byte[] data = new byte[heartBeatPrefix.length + heartBeatSuffix.length + heartBeatInfo.length];
107 | System.arraycopy(heartBeatPrefix, 0, data, 0, heartBeatPrefix.length);
108 | System.arraycopy(heartBeatInfo, 0, data, heartBeatPrefix.length, heartBeatInfo.length);
109 | System.arraycopy(heartBeatSuffix, 0, data, heartBeatPrefix.length + heartBeatInfo.length, heartBeatSuffix.length);
110 |
111 | return data;
112 | }
113 | });
114 |
115 | /**
116 | * 设置远程端发送到本地的心跳包信息的检测器,用于判断接收到的数据包是否是心跳包
117 | * 通过{@link SocketResponsePacket#isHeartBeat()} 查看数据包是否是心跳包
118 | */
119 | socketClient.getHeartBeatHelper().setReceiveHeartBeatPacketChecker(new SocketHeartBeatHelper.ReceiveHeartBeatPacketChecker() {
120 | @Override
121 | public boolean isReceiveHeartBeatPacket(SocketHeartBeatHelper helper, SocketResponsePacket packet) {
122 | /**
123 | * 判断数据包信息是否含有指定的心跳包前缀和后缀
124 | */
125 | byte[] heartBeatPrefix = new byte[]{0x1F, 0x1F};
126 | byte[] heartBeatSuffix = new byte[]{0x1F, 0x1F};
127 |
128 | if (Arrays.equals(heartBeatPrefix, Arrays.copyOfRange(packet.getData(), 0, heartBeatPrefix.length))
129 | && Arrays.equals(heartBeatSuffix, Arrays.copyOfRange(packet.getData(), packet.getData().length - heartBeatSuffix.length, packet.getData().length))) {
130 | return true;
131 | }
132 |
133 | return false;
134 | }
135 | });
136 |
137 | socketClient.getHeartBeatHelper().setHeartBeatInterval(10 * 1000); // 设置自动发送心跳包的间隔时长,单位毫秒
138 | socketClient.getHeartBeatHelper().setSendHeartBeatEnabled(true); // 设置允许自动发送心跳包,此值默认为false
139 | ```
140 |
141 | ### 自动按包尾分割信息读取数据的发送配置
142 | ```java
143 | /**
144 | * 根据连接双方协议设置自动发送的包尾数据
145 | * 每次发送数据包(包括心跳包)都会在发送包内容后自动发送此包尾
146 | *
147 | * 例:socketClient.sendData(new byte[]{0x01, 0x02})的步骤为
148 | * 1. socketClient向远程端发送包头(如果设置了包头信息)
149 | * 2. socketClient向远程端发送正文数据{0x01, 0x02}
150 | * 3. socketClient向远程端发送包尾
151 | *
152 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadToTrailer}必须设置此项
153 | * 用于分隔多条消息
154 | */
155 | socketClient.getSocketPacketHelper().setSendTrailerData(new byte[]{0x13, 0x10});
156 |
157 | /**
158 | * 根据连接双方协议设置自动发送的包头数据
159 | * 每次发送数据包(包括心跳包)都会在发送包内容前自动发送此包头
160 | *
161 | * 若无需包头可删除此行
162 | */
163 | socketClient.getSocketPacketHelper().setSendHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));
164 |
165 | /**
166 | * 设置分段发送数据长度
167 | * 即在发送指定长度后通过 {@link SocketClientSendingDelegate#onSendingPacketInProgress(SocketClient, SocketPacket, float, int)}回调当前发送进度
168 | *
169 | * 若无需进度回调可删除此二行,删除后仍有【发送开始】【发送结束】的回调
170 | */
171 | socketClient.getSocketPacketHelper().setSendSegmentLength(8); // 设置发送分段长度,单位byte
172 | socketClient.getSocketPacketHelper().setSendSegmentEnabled(true); // 设置允许使用分段发送,此值默认为false
173 |
174 | /**
175 | * 设置发送超时时长
176 | * 在发送每个数据包时,发送每段数据的最长时间,超过后自动断开socket连接
177 | * 通过设置分段发送{@link SocketPacketHelper#setSendSegmentEnabled(boolean)} 可避免发送大数据包时因超时断开,
178 | *
179 | * 若无需限制发送时长可删除此二行
180 | */
181 | socketClient.getSocketPacketHelper().setSendTimeout(30 * 1000); // 设置发送超时时长,单位毫秒
182 | socketClient.getSocketPacketHelper().setSendTimeoutEnabled(true); // 设置允许使用发送超时时长,此值默认为false
183 | ```
184 |
185 | ### 自动按包尾分割信息读取数据的接收配置
186 | ```java
187 | /**
188 | * 设置读取策略为自动读取到指定的包尾
189 | */
190 | socketClient.getSocketPacketHelper().setReadStrategy(SocketPacketHelper.ReadStrategy.AutoReadToTrailer);
191 |
192 | /**
193 | * 根据连接双方协议设置的包尾数据
194 | * 每次接收数据包(包括心跳包)都会在检测接收到与包尾数据相同的byte[]时回调一个数据包
195 | *
196 | * 例:自动接收远程端所发送的socketClient.sendData(new byte[]{0x01, 0x02})【{0x01, 0x02}为将要接收的数据】的步骤为
197 | * 1. socketClient接收包头(如果设置了包头信息)(接收方式为一直读取到与包头相同的byte[],即可能过滤掉包头前的多余信息)
198 | * 2. socketClient接收正文和包尾(接收方式为一直读取到与尾相同的byte[])
199 | * 3. socketClient回调数据包
200 | *
201 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadToTrailer}必须设置此项
202 | * 用于分隔多条消息
203 | */
204 | socketClient.getSocketPacketHelper().setReceiveTrailerData(new byte[]{0x13, 0x10});
205 |
206 | /**
207 | * 根据连接双方协议设置的包头数据
208 | * 每次接收数据包(包括心跳包)都会先接收此包头
209 | *
210 | * 若无需包头可删除此行
211 | */
212 | socketClient.getSocketPacketHelper().setReceiveHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));
213 |
214 | /**
215 | * 设置接收超时时长
216 | * 在指定时长内没有数据到达本地自动断开
217 | *
218 | * 若无需限制接收时长可删除此二行
219 | */
220 | socketClient.getSocketPacketHelper().setReceiveTimeout(120 * 1000); // 设置接收超时时长,单位毫秒
221 | socketClient.getSocketPacketHelper().setReceiveTimeoutEnabled(true); // 设置允许使用接收超时时长,此值默认为false
222 | ```
223 |
224 | ### 自动按包长度信息读取的发送配置
225 | ```java
226 | /**
227 | * 设置包长度转换器
228 | * 即每次发送数据时,将包头以外的数据长度转换为特定的byte[]发送到远程端用于解析还需要读取多少长度的数据
229 | *
230 | * 例:socketClient.sendData(new byte[]{0x01, 0x02})的步骤为
231 | * 1. socketClient向远程端发送包头(如果设置了包头信息)
232 | * 2. socketClient要发送的数据为{0x01, 0x02},长度为2(若设置了包尾,还需加上包尾的字节长度),通过此转换器将int类型的2转换为4字节的byte[],远程端也照此算法将4字节的byte[]转换为int值
233 | * 3. socketClient向远程端发送转换后的长度信息byte[]
234 | * 4. socketClient向远程端发送正文数据{0x01, 0x02}
235 | * 5. socketClient向远程端发送包尾(如果设置了包尾信息)
236 | *
237 | * 此转换器用于第二步
238 | *
239 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadByLength}必须设置此项
240 | * 用于分隔多条消息
241 | */
242 | socketClient.getSocketPacketHelper().setSendPacketLengthDataConvertor(new SocketPacketHelper.SendPacketLengthDataConvertor() {
243 | @Override
244 | public byte[] obtainSendPacketLengthDataForPacketLength(SocketPacketHelper helper, int packetLength) {
245 | /**
246 | * 简单将int转换为byte[]
247 | */
248 | byte[] data = new byte[4];
249 | data[3] = (byte) (packetLength & 0xFF);
250 | data[2] = (byte) ((packetLength >> 8) & 0xFF);
251 | data[1] = (byte) ((packetLength >> 16) & 0xFF);
252 | data[0] = (byte) ((packetLength >> 24) & 0xFF);
253 | return data;
254 | }
255 | });
256 |
257 | /**
258 | * 根据连接双方协议设置自动发送的包头数据
259 | * 每次发送数据包(包括心跳包)都会在发送包内容前自动发送此包头
260 | *
261 | * 若无需包头可删除此行
262 | */
263 | socketClient.getSocketPacketHelper().setSendHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));
264 |
265 | /**
266 | * 根据连接双方协议设置自动发送的包尾数据
267 | * 每次发送数据包(包括心跳包)都会在发送包内容后自动发送此包尾
268 | *
269 | * 若无需包尾可删除此行
270 | * 注意:
271 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadByLength}时不依赖包尾读取数据
272 | */
273 | socketClient.getSocketPacketHelper().setSendTrailerData(new byte[]{0x13, 0x10});
274 |
275 | /**
276 | * 设置分段发送数据长度
277 | * 即在发送指定长度后通过 {@link SocketClientSendingDelegate#onSendingPacketInProgress(SocketClient, SocketPacket, float, int)}回调当前发送进度
278 | *
279 | * 若无需进度回调可删除此二行,删除后仍有【发送开始】【发送结束】的回调
280 | */
281 | socketClient.getSocketPacketHelper().setSendSegmentLength(8); // 设置发送分段长度,单位byte
282 | socketClient.getSocketPacketHelper().setSendSegmentEnabled(true); // 设置允许使用分段发送,此值默认为false
283 |
284 | /**
285 | * 设置发送超时时长
286 | * 在发送每个数据包时,发送每段数据的最长时间,超过后自动断开socket连接
287 | * 通过设置分段发送{@link SocketPacketHelper#setSendSegmentEnabled(boolean)} 可避免发送大数据包时因超时断开,
288 | *
289 | * 若无需限制发送时长可删除此二行
290 | */
291 | socketClient.getSocketPacketHelper().setSendTimeout(30 * 1000); // 设置发送超时时长,单位毫秒
292 | socketClient.getSocketPacketHelper().setSendTimeoutEnabled(true); // 设置允许使用发送超时时长,此值默认为false
293 | ```
294 |
295 | ### 自动按包长度信息读取的接收配置
296 | ```java
297 | /**
298 | * 设置读取策略为自动读取指定长度
299 | */
300 | socketClient.getSocketPacketHelper().setReadStrategy(SocketPacketHelper.ReadStrategy.AutoReadByLength);
301 |
302 | /**
303 | * 设置包长度转换器
304 | * 即每次接收数据时,将远程端发送到本地的长度信息byte[]转换为int,然后读取相应长度的值
305 | *
306 | * 例:自动接收远程端所发送的socketClient.sendData(new byte[]{0x01, 0x02})【{0x01, 0x02}为将要接收的数据】的步骤为
307 | * 1. socketClient接收包头(如果设置了包头信息)(接收方式为一直读取到与包头相同的byte[],即可能过滤掉包头前的多余信息)
308 | * 2. socketClient接收长度为{@link SocketPacketHelper#getReceivePacketLengthDataLength()}(此处设置为4)的byte[],通过下面设置的转换器,将byte[]转换为int值,此int值暂时称为X
309 | * 3. socketClient接收长度为X的byte[]
310 | * 4. socketClient接收包尾(如果设置了包尾信息)(接收方式为一直读取到与包尾相同的byte[],如无意外情况,此处不会读取到多余的信息)
311 | * 5. socketClient回调数据包
312 | *
313 | * 此转换器用于第二步
314 | *
315 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadByLength}必须设置此项
316 | * 用于分隔多条消息
317 | */
318 | socketClient.getSocketPacketHelper().setReceivePacketLengthDataLength(4);
319 | socketClient.getSocketPacketHelper().setReceivePacketDataLengthConvertor(new SocketPacketHelper.ReceivePacketDataLengthConvertor() {
320 | @Override
321 | public int obtainReceivePacketDataLength(SocketPacketHelper helper, byte[] packetLengthData) {
322 | /**
323 | * 简单将byte[]转换为int
324 | */
325 | int length = (packetLengthData[3] & 0xFF) + ((packetLengthData[2] & 0xFF) << 8) + ((packetLengthData[1] & 0xFF) << 16) + ((packetLengthData[0] & 0xFF) << 24);
326 |
327 | return length;
328 | }
329 | });
330 |
331 | /**
332 | * 根据连接双方协议设置的包头数据
333 | * 每次接收数据包(包括心跳包)都会先接收此包头
334 | *
335 | * 若无需包头可删除此行
336 | */
337 | socketClient.getSocketPacketHelper().setReceiveHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));
338 |
339 | /**
340 | * 根据连接双方协议设置的包尾数据
341 | *
342 | * 若无需包尾可删除此行
343 | * 注意:
344 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadByLength}时不依赖包尾读取数据
345 | */
346 | socketClient.getSocketPacketHelper().setReceiveTrailerData(new byte[]{0x13, 0x10});
347 |
348 | /**
349 | * 设置接收超时时长
350 | * 在指定时长内没有数据到达本地自动断开
351 | *
352 | * 若无需限制接收时长可删除此二行
353 | */
354 | socketClient.getSocketPacketHelper().setReceiveTimeout(120 * 1000); // 设置接收超时时长,单位毫秒
355 | socketClient.getSocketPacketHelper().setReceiveTimeoutEnabled(true); // 设置允许使用接收超时时长,此值默认为false
356 | ```
357 |
358 | ### 手动读取的发送配置
359 | ```java
360 | /**
361 | * 设置分段发送数据长度
362 | * 即在发送指定长度后通过 {@link SocketClientSendingDelegate#onSendingPacketInProgress(SocketClient, SocketPacket, float, int)}回调当前发送进度
363 | *
364 | * 若无需进度回调可删除此二行,删除后仍有【发送开始】【发送结束】的回调
365 | */
366 | socketClient.getSocketPacketHelper().setSendSegmentLength(8); // 设置发送分段长度,单位byte
367 | socketClient.getSocketPacketHelper().setSendSegmentEnabled(true); // 设置允许使用分段发送,此值默认为false
368 |
369 | /**
370 | * 设置发送超时时长
371 | * 在发送每个数据包时,发送每段数据的最长时间,超过后自动断开socket连接
372 | * 通过设置分段发送{@link SocketPacketHelper#setSendSegmentEnabled(boolean)} 可避免发送大数据包时因超时断开,
373 | *
374 | * 若无需限制发送时长可删除此二行
375 | */
376 | socketClient.getSocketPacketHelper().setSendTimeout(30 * 1000); // 设置发送超时时长,单位毫秒
377 | socketClient.getSocketPacketHelper().setSendTimeoutEnabled(true); // 设置允许使用发送超时时长,此值默认为false
378 | ```
379 |
380 | ### 手动读取的接收配置
381 | ```java
382 | /**
383 | * 设置读取策略为手动读取
384 | * 手动读取有两种方法
385 | * 1. {@link SocketClient#readDataToData(byte[], boolean)} )} 读取到与指定字节相同的字节序列后回调数据包
386 | * 2. {@link SocketClient#readDataToLength(int)} 读取指定长度的字节后回调数据包
387 | *
388 | * 此时SocketPacketHelper中其他读取相关设置将会无效化
389 | */
390 | socketClient.getSocketPacketHelper().setReadStrategy(SocketPacketHelper.ReadStrategy.Manually);
391 | ```
392 |
393 | ### 常用回调配置
394 | ```java
395 | // 对应removeSocketClientDelegate
396 | socketClient.registerSocketClientDelegate(new SocketClientDelegate() {
397 | /**
398 | * 连接上远程端时的回调
399 | */
400 | @Override
401 | public void onConnected(SocketClient client) {
402 | SocketPacket packet = socketClient.sendData(new byte[]{0x02}); // 发送消息
403 | packet = socketClient.sendString("sy hi!"); // 发送消息
404 |
405 | socketClient.cancelSend(packet); // 取消发送,若在等待发送队列中则从队列中移除,若正在发送则无法取消
406 | }
407 |
408 | /**
409 | * 与远程端断开连接时的回调
410 | */
411 | @Override
412 | public void onDisconnected(SocketClient client) {
413 | // 可在此实现自动重连
414 | socketClient.connect();
415 | }
416 |
417 | /**
418 | * 接收到数据包时的回调
419 | */
420 | @Override
421 | public void onResponse(final SocketClient client, @NonNull SocketResponsePacket responsePacket) {
422 | byte[] data = responsePacket.getData(); // 获取接收的byte数组,不为null
423 | String message = responsePacket.getMessage(); // 获取按默认设置的编码转化的String,可能为null
424 | }
425 | });
426 | ```
427 |
428 | ### 发送状态回调配置
429 | ```java
430 | // 对应removeSocketClientSendingDelegate
431 | socketClient.registerSocketClientSendingDelegate(new SocketClientSendingDelegate() {
432 | /**
433 | * 数据包开始发送时的回调
434 | */
435 | @Override
436 | public void onSendPacketBegin(SocketClient client, SocketPacket packet) {
437 | }
438 |
439 | /**
440 | * 数据包取消发送时的回调
441 | * 取消发送回调有以下情况:
442 | * 1. 手动cancel仍在排队,还未发送过的packet
443 | * 2. 断开连接时,正在发送的packet和所有在排队的packet都会被取消
444 | */
445 | @Override
446 | public void onSendPacketCancel(SocketClient client, SocketPacket packet) {
447 | }
448 |
449 | /**
450 | * 数据包发送的进度回调
451 | * progress值为[0.0f, 1.0f]
452 | * 通常配合分段发送使用
453 | * 可用于显示文件等大数据的发送进度
454 | */
455 | @Override
456 | public void onSendingPacketInProgress(SocketClient client, SocketPacket packet, float progress, int sendedLength) {
457 | }
458 |
459 | /**
460 | * 数据包完成发送时的回调
461 | */
462 | @Override
463 | public void onSendPacketEnd(SocketClient client, SocketPacket packet) {
464 | }
465 | });
466 | ```
467 |
468 | ### 接收状态回调配置
469 | ```java
470 | // 对应removeSocketClientReceiveDelegate
471 | socketClient.registerSocketClientReceiveDelegate(new SocketClientReceivingDelegate() {
472 | /**
473 | * 开始接受一个新的数据包时的回调
474 | */
475 | @Override
476 | public void onReceivePacketBegin(SocketClient client, SocketResponsePacket packet) {
477 | }
478 |
479 | /**
480 | * 完成接受一个新的数据包时的回调
481 | */
482 | @Override
483 | public void onReceivePacketEnd(SocketClient client, SocketResponsePacket packet) {
484 | }
485 |
486 | /**
487 | * 取消接受一个新的数据包时的回调
488 | * 在断开连接时会触发
489 | */
490 | @Override
491 | public void onReceivePacketCancel(SocketClient client, SocketResponsePacket packet) {
492 | }
493 |
494 | /**
495 | * 接受一个新的数据包的进度回调
496 | * progress值为[0.0f, 1.0f]
497 | * 仅作用于ReadStrategy为AutoReadByLength的自动读取
498 | * 因AutoReadByLength可以首先接受到剩下的数据包长度
499 | */
500 | @Override
501 | public void onReceivingPacketInProgress(SocketClient client, SocketResponsePacket packet, float progress, int receivedLength) {
502 | }
503 | });
504 | ```
505 |
506 | ## License
507 | [Apache License Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt)
508 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | generateDebugSources
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.2"
6 |
7 | defaultConfig {
8 | applicationId "com.vilyever.androidsocketclient"
9 | minSdkVersion 16
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | compile 'com.android.support:appcompat-v7:23.1.1'
25 |
26 | compile project(":socketclient")
27 | compile 'com.github.vilyever:AndroidLogger:1.0.9'
28 | compile 'com.github.vilyever:AndroidJsonModel:1.2.0'
29 | }
30 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\Development\Android\Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/vilyever/androidsocketclient/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.androidsocketclient;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/vilyever/androidsocketclient/App.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.androidsocketclient;
2 |
3 | import android.app.Application;
4 |
5 | import com.vilyever.logger.Logger;
6 | import com.vilyever.logger.LoggerDisplay;
7 |
8 | /**
9 | * App
10 | * AndroidSocketClient
11 | * Created by vilyever on 2016/3/30.
12 | * Feature:
13 | */
14 | public class App extends Application {
15 | final App self = this;
16 |
17 |
18 | /* Constructors */
19 |
20 |
21 | /* Public Methods */
22 |
23 |
24 | /* Properties */
25 |
26 |
27 | /* Overrides */
28 |
29 | @Override
30 | public void onCreate() {
31 | super.onCreate();
32 |
33 | LoggerDisplay.initialize(this);
34 | LoggerDisplay.setDisplayLogTag(Logger.DefaultTag);
35 | }
36 |
37 | /* Delegates */
38 |
39 |
40 | /* Private Methods */
41 |
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/vilyever/androidsocketclient/FileUtil.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.androidsocketclient;
2 |
3 | import com.vilyever.contextholder.ContextHolder;
4 |
5 | import java.io.File;
6 |
7 | /**
8 | * FileUtil
9 | * Created by vilyever on 2016/6/1.
10 | * Feature:
11 | */
12 | public class FileUtil {
13 | final FileUtil self = this;
14 |
15 |
16 | /* Constructors */
17 |
18 |
19 | /* Public Methods */
20 | public static File getCacheDir() {
21 | File dir = null;
22 | dir = ContextHolder.getContext().getExternalCacheDir();
23 | if (dir != null && dir.isDirectory()) {
24 | return dir;
25 | }
26 |
27 | dir = ContextHolder.getContext().getCacheDir();
28 | if (dir != null && dir.isDirectory()) {
29 | return dir;
30 | }
31 |
32 | return dir;
33 | }
34 |
35 | /* Properties */
36 |
37 |
38 | /* Overrides */
39 |
40 |
41 | /* Delegates */
42 |
43 |
44 | /* Private Methods */
45 |
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/vilyever/androidsocketclient/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.androidsocketclient;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.util.Log;
6 | import android.widget.ImageView;
7 |
8 | import java.nio.ByteBuffer;
9 |
10 | public class MainActivity extends AppCompatActivity {
11 | final MainActivity self = this;
12 |
13 | private ImageView imageView;
14 | protected ImageView getImageView() { if (this.imageView == null) { this.imageView = (ImageView) findViewById(R.id.imageView); } return this.imageView; }
15 |
16 | private TestServer testServer;
17 | protected TestServer getTestServer() {
18 | if (this.testServer == null) {
19 | this.testServer = new TestServer();
20 | }
21 | return this.testServer;
22 | }
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.activity_main);
28 |
29 | Log.d("logger", "ts " + bytesToHex(encodeUINT16(18005)));
30 | Log.d("logger", "ts " + bytesToHex(encodeUINT16(18005)));
31 |
32 | getTestServer().beginListen();
33 | }
34 |
35 | public byte[] encodeUINT16(int param) {
36 | byte[] bytes = ByteBuffer.allocate(4).putInt(param ^ 0xADAD).array();
37 |
38 | byte[] encodedBytes = new byte[2];
39 | encodedBytes[0] = bytes[3];
40 | encodedBytes[1] = bytes[2];
41 | return encodedBytes;
42 | }
43 |
44 | final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
45 | public static String bytesToHex(byte[] bytes) {
46 | char[] hexChars = new char[bytes.length * 2];
47 | for ( int j = 0; j < bytes.length; j++ ) {
48 | int v = bytes[j] & 0xFF;
49 | hexChars[j * 2] = hexArray[v >>> 4];
50 | hexChars[j * 2 + 1] = hexArray[v & 0x0F];
51 | }
52 | return new String(hexChars);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/vilyever/androidsocketclient/TestClient.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.androidsocketclient;
2 |
3 | import android.os.AsyncTask;
4 | import android.support.annotation.NonNull;
5 |
6 | import com.vilyever.logger.Logger;
7 | import com.vilyever.socketclient.SocketClient;
8 | import com.vilyever.socketclient.helper.SocketClientDelegate;
9 | import com.vilyever.socketclient.helper.SocketClientReceivingDelegate;
10 | import com.vilyever.socketclient.helper.SocketClientSendingDelegate;
11 | import com.vilyever.socketclient.helper.SocketHeartBeatHelper;
12 | import com.vilyever.socketclient.helper.SocketPacket;
13 | import com.vilyever.socketclient.helper.SocketPacketHelper;
14 | import com.vilyever.socketclient.helper.SocketResponsePacket;
15 | import com.vilyever.socketclient.util.CharsetUtil;
16 | import com.vilyever.socketclient.util.IPUtil;
17 |
18 | import java.text.SimpleDateFormat;
19 | import java.util.Arrays;
20 | import java.util.Date;
21 |
22 | /**
23 | * TestClient
24 | * Created by vilyever on 2016/7/26.
25 | * Feature:
26 | */
27 | public class TestClient {
28 | final TestClient self = this;
29 |
30 |
31 | /* Constructors */
32 |
33 |
34 | /* Public Methods */
35 | public void connect() {
36 | self.getLocalSocketClient().connect();
37 | }
38 |
39 | /* Properties */
40 | private SocketClient localSocketClient;
41 | public SocketClient getLocalSocketClient() {
42 | if (this.localSocketClient == null) {
43 | this.localSocketClient = new SocketClient();
44 |
45 | __i__setupAddress(this.localSocketClient);
46 | __i__setupEncoding(this.localSocketClient);
47 |
48 | __i__setupConstantHeartBeat(this.localSocketClient);
49 |
50 | // __i__setupVariableHeartBeat(this.localSocketClient);
51 |
52 | // __i__setupReadToTrailerForSender(this.localSocketClient);
53 | // __i__setupReadToTrailerForReceiver(this.localSocketClient);
54 |
55 | __i__setupReadByLengthForSender(this.localSocketClient);
56 | __i__setupReadByLengthForReceiver(this.localSocketClient);
57 |
58 | // __i__setupReadManuallyForSender(this.localSocketClient);
59 | // __i__setupReadManuallyForReceiver(this.localSocketClient);
60 |
61 | this.localSocketClient.registerSocketClientDelegate(new SocketClientDelegate() {
62 | @Override
63 | public void onConnected(SocketClient client) {
64 | Logger.log("onConnected", "SocketClient: onConnected");
65 |
66 | if (client.getSocketPacketHelper().getReadStrategy() == SocketPacketHelper.ReadStrategy.Manually) {
67 | client.readDataToLength(CharsetUtil.stringToData("Server accepted", CharsetUtil.UTF_8).length);
68 | }
69 | }
70 |
71 | @Override
72 | public void onDisconnected(final SocketClient client) {
73 | Logger.log("onDisconnected", "SocketClient: onDisconnected");
74 |
75 | new AsyncTask() {
76 | @Override
77 | protected Void doInBackground(Void... params) {
78 | try {
79 | Thread.sleep(3 * 1000);
80 | }
81 | catch (InterruptedException e) {
82 | e.printStackTrace();
83 | }
84 |
85 | client.connect();
86 |
87 | return null;
88 | }
89 |
90 | @Override
91 | protected void onPostExecute(Void aVoid) {
92 | super.onPostExecute(aVoid);
93 |
94 | }
95 | }.execute();
96 | }
97 |
98 | @Override
99 | public void onResponse(final SocketClient client, @NonNull SocketResponsePacket responsePacket) {
100 | Logger.log("onResponse", "SocketClient: onResponse: " + responsePacket.hashCode() + " 【" + responsePacket.getMessage() + "】 " + " isHeartBeat: " + responsePacket.isHeartBeat() + " " + Arrays.toString(responsePacket.getData()));
101 | if (responsePacket.isHeartBeat()) {
102 | return;
103 | }
104 | new AsyncTask() {
105 | @Override
106 | protected Void doInBackground(Void... params) {
107 | try {
108 | Thread.sleep(3 * 1000);
109 | }
110 | catch (InterruptedException e) {
111 | e.printStackTrace();
112 | }
113 |
114 | client.sendString("client on " + System.currentTimeMillis());
115 |
116 | try {
117 | Thread.sleep(3 * 1000);
118 | }
119 | catch (InterruptedException e) {
120 | e.printStackTrace();
121 | }
122 |
123 | client.disconnect();
124 |
125 | return null;
126 | }
127 |
128 | @Override
129 | protected void onPostExecute(Void aVoid) {
130 | super.onPostExecute(aVoid);
131 |
132 | }
133 | }.execute();
134 | }
135 | });
136 | this.localSocketClient.registerSocketClientSendingDelegate(new SocketClientSendingDelegate() {
137 |
138 | @Override
139 | public void onSendPacketBegin(SocketClient client, SocketPacket packet) {
140 | Logger.log("onSend", "SocketClient: onSendPacketBegin: " + packet.hashCode() + " " + Arrays.toString(packet.getData()));
141 | }
142 |
143 | @Override
144 | public void onSendPacketCancel(SocketClient client, SocketPacket packet) {
145 | Logger.log("onSend", "SocketClient: onSendPacketCancel: " + packet.hashCode());
146 | }
147 |
148 | @Override
149 | public void onSendingPacketInProgress(SocketClient client, SocketPacket packet, float progress, int sendedLength) {
150 | Logger.log("onSend", "SocketClient: onSendingPacketInProgress: " + packet.hashCode() + " : " + progress + " : " + sendedLength);
151 | }
152 |
153 | @Override
154 | public void onSendPacketEnd(SocketClient client, SocketPacket packet) {
155 | Logger.log("onSend", "SocketClient: onSendPacketEnd: " + packet.hashCode());
156 | }
157 | });
158 | this.localSocketClient.registerSocketClientReceiveDelegate(new SocketClientReceivingDelegate() {
159 | @Override
160 | public void onReceivePacketBegin(SocketClient client, SocketResponsePacket packet) {
161 | Logger.log("onReceive", "SocketClient: onReceivePacketBegin: " + packet.hashCode());
162 | }
163 |
164 | @Override
165 | public void onReceivePacketEnd(SocketClient client, SocketResponsePacket packet) {
166 | Logger.log("onReceive", "SocketClient: onReceivePacketEnd: " + packet.hashCode());
167 | }
168 |
169 | @Override
170 | public void onReceivePacketCancel(SocketClient client, SocketResponsePacket packet) {
171 | Logger.log("onReceive", "SocketClient: onReceivePacketCancel: " + packet.hashCode());
172 | }
173 |
174 | @Override
175 | public void onReceivingPacketInProgress(SocketClient client, SocketResponsePacket packet, float progress, int receivedLength) {
176 | Logger.log("onReceive", "SocketClient: onReceivingPacketInProgress: " + packet.hashCode() + " : " + progress + " : " + receivedLength);
177 | }
178 | });
179 | }
180 | return this.localSocketClient;
181 | }
182 |
183 | /* Overrides */
184 |
185 |
186 | /* Delegates */
187 |
188 |
189 | /* Private Methods */
190 | /**
191 | * 设置远程端地址信息
192 | */
193 | private void __i__setupAddress(SocketClient socketClient) {
194 | socketClient.getAddress().setRemoteIP(IPUtil.getLocalIPAddress(true)); // 远程端IP地址
195 | socketClient.getAddress().setRemotePort("21998"); // 远程端端口号
196 | socketClient.getAddress().setConnectionTimeout(15 * 1000); // 连接超时时长,单位毫秒
197 | }
198 |
199 | /**
200 | * 设置自动转换String类型到byte[]类型的编码
201 | * 如未设置(默认为null),将不能使用{@link SocketClient#sendString(String)}发送消息
202 | * 如设置为非null(如UTF-8),在接受消息时会自动尝试在接收线程(非主线程)将接收的byte[]数据依照编码转换为String,在{@link SocketResponsePacket#getMessage()}读取
203 | */
204 | private void __i__setupEncoding(SocketClient socketClient) {
205 | socketClient.setCharsetName(CharsetUtil.UTF_8); // 设置编码为UTF-8
206 | }
207 |
208 | private void __i__setupConstantHeartBeat(SocketClient socketClient) {
209 | /**
210 | * 设置自动发送的心跳包信息
211 | */
212 | socketClient.getHeartBeatHelper().setDefaultSendData(CharsetUtil.stringToData("HeartBeat", CharsetUtil.UTF_8));
213 |
214 | /**
215 | * 设置远程端发送到本地的心跳包信息内容,用于判断接收到的数据包是否是心跳包
216 | * 通过{@link SocketResponsePacket#isHeartBeat()} 查看数据包是否是心跳包
217 | */
218 | socketClient.getHeartBeatHelper().setDefaultReceiveData(CharsetUtil.stringToData("HeartBeat", CharsetUtil.UTF_8));
219 | socketClient.getHeartBeatHelper().setHeartBeatInterval(10 * 1000); // 设置自动发送心跳包的间隔时长,单位毫秒
220 | socketClient.getHeartBeatHelper().setSendHeartBeatEnabled(true); // 设置允许自动发送心跳包,此值默认为false
221 | }
222 |
223 | private void __i__setupVariableHeartBeat(SocketClient socketClient) {
224 | /**
225 | * 设置自动发送的心跳包信息
226 | * 此信息动态生成
227 | *
228 | * 每次发送心跳包时自动调用
229 | */
230 | socketClient.getHeartBeatHelper().setSendDataBuilder(new SocketHeartBeatHelper.SendDataBuilder() {
231 | @Override
232 | public byte[] obtainSendHeartBeatData(SocketHeartBeatHelper helper) {
233 | /**
234 | * 使用当前日期作为心跳包
235 | */
236 | byte[] heartBeatPrefix = new byte[]{0x1F, 0x1F};
237 | byte[] heartBeatSuffix = new byte[]{0x1F, 0x1F};
238 |
239 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
240 | byte[] heartBeatInfo = CharsetUtil.stringToData(sdf.format(new Date()), CharsetUtil.UTF_8);
241 |
242 | byte[] data = new byte[heartBeatPrefix.length + heartBeatSuffix.length + heartBeatInfo.length];
243 | System.arraycopy(heartBeatPrefix, 0, data, 0, heartBeatPrefix.length);
244 | System.arraycopy(heartBeatInfo, 0, data, heartBeatPrefix.length, heartBeatInfo.length);
245 | System.arraycopy(heartBeatSuffix, 0, data, heartBeatPrefix.length + heartBeatInfo.length, heartBeatSuffix.length);
246 |
247 | return data;
248 | }
249 | });
250 |
251 | /**
252 | * 设置远程端发送到本地的心跳包信息的检测器,用于判断接收到的数据包是否是心跳包
253 | * 通过{@link SocketResponsePacket#isHeartBeat()} 查看数据包是否是心跳包
254 | */
255 | socketClient.getHeartBeatHelper().setReceiveHeartBeatPacketChecker(new SocketHeartBeatHelper.ReceiveHeartBeatPacketChecker() {
256 | @Override
257 | public boolean isReceiveHeartBeatPacket(SocketHeartBeatHelper helper, SocketResponsePacket packet) {
258 | /**
259 | * 判断数据包信息是否含有指定的心跳包前缀和后缀
260 | */
261 | byte[] heartBeatPrefix = new byte[]{0x1F, 0x1F};
262 | byte[] heartBeatSuffix = new byte[]{0x1F, 0x1F};
263 |
264 | if (Arrays.equals(heartBeatPrefix, Arrays.copyOfRange(packet.getData(), 0, heartBeatPrefix.length))
265 | && Arrays.equals(heartBeatSuffix, Arrays.copyOfRange(packet.getData(), packet.getData().length - heartBeatSuffix.length, packet.getData().length))) {
266 | return true;
267 | }
268 |
269 | return false;
270 | }
271 | });
272 |
273 | socketClient.getHeartBeatHelper().setHeartBeatInterval(10 * 1000); // 设置自动发送心跳包的间隔时长,单位毫秒
274 | socketClient.getHeartBeatHelper().setSendHeartBeatEnabled(true); // 设置允许自动发送心跳包,此值默认为false
275 | }
276 |
277 | private void __i__setupReadToTrailerForSender(SocketClient socketClient) {
278 | /**
279 | * 根据连接双方协议设置自动发送的包尾数据
280 | * 每次发送数据包(包括心跳包)都会在发送包内容后自动发送此包尾
281 | *
282 | * 例:socketClient.sendData(new byte[]{0x01, 0x02})的步骤为
283 | * 1. socketClient向远程端发送包头(如果设置了包头信息)
284 | * 2. socketClient向远程端发送正文数据{0x01, 0x02}
285 | * 3. socketClient向远程端发送包尾
286 | *
287 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadToTrailer}必须设置此项
288 | * 用于分隔多条消息
289 | */
290 | socketClient.getSocketPacketHelper().setSendTrailerData(new byte[]{0x13, 0x10});
291 |
292 | /**
293 | * 根据连接双方协议设置自动发送的包头数据
294 | * 每次发送数据包(包括心跳包)都会在发送包内容前自动发送此包头
295 | *
296 | * 若无需包头可删除此行
297 | */
298 | socketClient.getSocketPacketHelper().setSendHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));
299 |
300 | /**
301 | * 设置分段发送数据长度
302 | * 即在发送指定长度后通过 {@link SocketClientSendingDelegate#onSendingPacketInProgress(SocketClient, SocketPacket, float, int)}回调当前发送进度
303 | * 注意:回调过于频繁可能导致设置UI过于频繁从而导致主线程卡顿
304 | *
305 | * 若无需进度回调可删除此二行,删除后仍有【发送开始】【发送结束】的回调
306 | */
307 | socketClient.getSocketPacketHelper().setSendSegmentLength(8); // 设置发送分段长度,单位byte
308 | socketClient.getSocketPacketHelper().setSendSegmentEnabled(true); // 设置允许使用分段发送,此值默认为false
309 |
310 | /**
311 | * 设置发送超时时长
312 | * 在发送每个数据包时,发送每段数据的最长时间,超过后自动断开socket连接
313 | * 通过设置分段发送{@link SocketPacketHelper#setSendSegmentEnabled(boolean)} 可避免发送大数据包时因超时断开,
314 | *
315 | * 若无需限制发送时长可删除此二行
316 | */
317 | socketClient.getSocketPacketHelper().setSendTimeout(30 * 1000); // 设置发送超时时长,单位毫秒
318 | socketClient.getSocketPacketHelper().setSendTimeoutEnabled(true); // 设置允许使用发送超时时长,此值默认为false
319 | }
320 |
321 | private void __i__setupReadToTrailerForReceiver(SocketClient socketClient) {
322 | /**
323 | * 设置读取策略为自动读取到指定的包尾
324 | */
325 | socketClient.getSocketPacketHelper().setReadStrategy(SocketPacketHelper.ReadStrategy.AutoReadToTrailer);
326 |
327 | /**
328 | * 根据连接双方协议设置的包尾数据
329 | * 每次接收数据包(包括心跳包)都会在检测接收到与包尾数据相同的byte[]时回调一个数据包
330 | *
331 | * 例:自动接收远程端所发送的socketClient.sendData(new byte[]{0x01, 0x02})【{0x01, 0x02}为将要接收的数据】的步骤为
332 | * 1. socketClient接收包头(如果设置了包头信息)(接收方式为一直读取到与包头相同的byte[],即可能过滤掉包头前的多余信息)
333 | * 2. socketClient接收正文和包尾(接收方式为一直读取到与尾相同的byte[])
334 | * 3. socketClient回调数据包
335 | *
336 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadToTrailer}必须设置此项
337 | * 用于分隔多条消息
338 | */
339 | socketClient.getSocketPacketHelper().setReceiveTrailerData(new byte[]{0x13, 0x10});
340 |
341 | /**
342 | * 根据连接双方协议设置的包头数据
343 | * 每次接收数据包(包括心跳包)都会先接收此包头
344 | *
345 | * 若无需包头可删除此行
346 | */
347 | socketClient.getSocketPacketHelper().setReceiveHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));
348 |
349 | /**
350 | * 设置接收超时时长
351 | * 在指定时长内没有数据到达本地自动断开
352 | *
353 | * 若无需限制接收时长可删除此二行
354 | */
355 | socketClient.getSocketPacketHelper().setReceiveTimeout(120 * 1000); // 设置接收超时时长,单位毫秒
356 | socketClient.getSocketPacketHelper().setReceiveTimeoutEnabled(true); // 设置允许使用接收超时时长,此值默认为false
357 | }
358 |
359 | private void __i__setupReadByLengthForSender(SocketClient socketClient) {
360 | /**
361 | * 设置包长度转换器
362 | * 即每次发送数据时,将包头以外的数据长度转换为特定的byte[]发送个远程端用于解析还需要读取多少长度的数据
363 | *
364 | * 例:socketClient.sendData(new byte[]{0x01, 0x02})的步骤为
365 | * 1. socketClient向远程端发送包头(如果设置了包头信息)
366 | * 2. socketClient要发送的数据为{0x01, 0x02},长度为2(若设置了包尾,还需加上包尾的字节长度),通过此转换器将int类型的2转换为4字节的byte[],远程端也照此算法将4字节的byte[]转换为int值
367 | * 3. socketClient向远程端发送转换后的长度信息byte[]
368 | * 4. socketClient向远程端发送正文数据{0x01, 0x02}
369 | * 5. socketClient向远程端发送包尾(如果设置了包尾信息)
370 | *
371 | * 此转换器用于第二步
372 | *
373 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadByLength}必须设置此项
374 | * 用于分隔多条消息
375 | */
376 | socketClient.getSocketPacketHelper().setSendPacketLengthDataConvertor(new SocketPacketHelper.SendPacketLengthDataConvertor() {
377 | @Override
378 | public byte[] obtainSendPacketLengthDataForPacketLength(SocketPacketHelper helper, int packetLength) {
379 | /**
380 | * 简单将int转换为byte[]
381 | */
382 | byte[] data = new byte[4];
383 | data[3] = (byte) (packetLength & 0xFF);
384 | data[2] = (byte) ((packetLength >> 8) & 0xFF);
385 | data[1] = (byte) ((packetLength >> 16) & 0xFF);
386 | data[0] = (byte) ((packetLength >> 24) & 0xFF);
387 | return data;
388 | }
389 | });
390 |
391 | /**
392 | * 根据连接双方协议设置自动发送的包头数据
393 | * 每次发送数据包(包括心跳包)都会在发送包内容前自动发送此包头
394 | *
395 | * 若无需包头可删除此行
396 | */
397 | socketClient.getSocketPacketHelper().setSendHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));
398 |
399 | /**
400 | * 根据连接双方协议设置自动发送的包尾数据
401 | * 每次发送数据包(包括心跳包)都会在发送包内容后自动发送此包尾
402 | *
403 | * 若无需包尾可删除此行
404 | * 注意:
405 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadByLength}时不依赖包尾读取数据
406 | */
407 | socketClient.getSocketPacketHelper().setSendTrailerData(new byte[]{0x13, 0x10});
408 |
409 | /**
410 | * 设置分段发送数据长度
411 | * 即在发送指定长度后通过 {@link SocketClientSendingDelegate#onSendingPacketInProgress(SocketClient, SocketPacket, float, int)}回调当前发送进度
412 | * 注意:回调过于频繁可能导致设置UI过于频繁从而导致主线程卡顿
413 | *
414 | * 若无需进度回调可删除此二行,删除后仍有【发送开始】【发送结束】的回调
415 | */
416 | socketClient.getSocketPacketHelper().setSendSegmentLength(8); // 设置发送分段长度,单位byte
417 | socketClient.getSocketPacketHelper().setSendSegmentEnabled(true); // 设置允许使用分段发送,此值默认为false
418 |
419 | /**
420 | * 设置发送超时时长
421 | * 在发送每个数据包时,发送每段数据的最长时间,超过后自动断开socket连接
422 | * 通过设置分段发送{@link SocketPacketHelper#setSendSegmentEnabled(boolean)} 可避免发送大数据包时因超时断开,
423 | *
424 | * 若无需限制发送时长可删除此二行
425 | */
426 | socketClient.getSocketPacketHelper().setSendTimeout(30 * 1000); // 设置发送超时时长,单位毫秒
427 | socketClient.getSocketPacketHelper().setSendTimeoutEnabled(true); // 设置允许使用发送超时时长,此值默认为false
428 | }
429 |
430 | private void __i__setupReadByLengthForReceiver(SocketClient socketClient) {
431 | /**
432 | * 设置读取策略为自动读取指定长度
433 | */
434 | socketClient.getSocketPacketHelper().setReadStrategy(SocketPacketHelper.ReadStrategy.AutoReadByLength);
435 |
436 | /**
437 | * 设置包长度转换器
438 | * 即每次接收数据时,将远程端发送到本地的长度信息byte[]转换为int,然后读取相应长度的值
439 | *
440 | * 例:自动接收远程端所发送的socketClient.sendData(new byte[]{0x01, 0x02})【{0x01, 0x02}为将要接收的数据】的步骤为
441 | * 1. socketClient接收包头(如果设置了包头信息)(接收方式为一直读取到与包头相同的byte[],即可能过滤掉包头前的多余信息)
442 | * 2. socketClient接收长度为{@link SocketPacketHelper#getReceivePacketLengthDataLength()}(此处设置为4)的byte[],通过下面设置的转换器,将byte[]转换为int值,此int值暂时称为X
443 | * 3. socketClient接收长度为X的byte[]
444 | * 4. socketClient接收包尾(如果设置了包尾信息)(接收方式为一直读取到与包尾相同的byte[],如无意外情况,此处不会读取到多余的信息)
445 | * 5. socketClient回调数据包
446 | *
447 | * 此转换器用于第二步
448 | *
449 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadByLength}必须设置此项
450 | * 用于分隔多条消息
451 | */
452 | socketClient.getSocketPacketHelper().setReceivePacketLengthDataLength(4);
453 | socketClient.getSocketPacketHelper().setReceivePacketDataLengthConvertor(new SocketPacketHelper.ReceivePacketDataLengthConvertor() {
454 | @Override
455 | public int obtainReceivePacketDataLength(SocketPacketHelper helper, byte[] packetLengthData) {
456 | /**
457 | * 简单将byte[]转换为int
458 | */
459 | int length = (packetLengthData[3] & 0xFF) + ((packetLengthData[2] & 0xFF) << 8) + ((packetLengthData[1] & 0xFF) << 16) + ((packetLengthData[0] & 0xFF) << 24);
460 |
461 | return length;
462 | }
463 | });
464 |
465 | /**
466 | * 根据连接双方协议设置的包头数据
467 | * 每次接收数据包(包括心跳包)都会先接收此包头
468 | *
469 | * 若无需包头可删除此行
470 | */
471 | socketClient.getSocketPacketHelper().setReceiveHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));
472 |
473 | /**
474 | * 根据连接双方协议设置的包尾数据
475 | *
476 | * 若无需包尾可删除此行
477 | * 注意:
478 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadByLength}时不依赖包尾读取数据
479 | */
480 | socketClient.getSocketPacketHelper().setReceiveTrailerData(new byte[]{0x13, 0x10});
481 |
482 | /**
483 | * 设置接收超时时长
484 | * 在指定时长内没有数据到达本地自动断开
485 | *
486 | * 若无需限制接收时长可删除此二行
487 | */
488 | socketClient.getSocketPacketHelper().setReceiveTimeout(120 * 1000); // 设置接收超时时长,单位毫秒
489 | socketClient.getSocketPacketHelper().setReceiveTimeoutEnabled(true); // 设置允许使用接收超时时长,此值默认为false
490 | }
491 |
492 | private void __i__setupReadManuallyForSender(SocketClient socketClient) {
493 | /**
494 | * 设置分段发送数据长度
495 | * 即在发送指定长度后通过 {@link SocketClientSendingDelegate#onSendingPacketInProgress(SocketClient, SocketPacket, float, int)}回调当前发送进度
496 | * 注意:回调过于频繁可能导致设置UI过于频繁从而导致主线程卡顿
497 | *
498 | * 若无需进度回调可删除此二行,删除后仍有【发送开始】【发送结束】的回调
499 | */
500 | socketClient.getSocketPacketHelper().setSendSegmentLength(8); // 设置发送分段长度,单位byte
501 | socketClient.getSocketPacketHelper().setSendSegmentEnabled(true); // 设置允许使用分段发送,此值默认为false
502 |
503 | /**
504 | * 设置发送超时时长
505 | * 在发送每个数据包时,发送每段数据的最长时间,超过后自动断开socket连接
506 | * 通过设置分段发送{@link SocketPacketHelper#setSendSegmentEnabled(boolean)} 可避免发送大数据包时因超时断开,
507 | *
508 | * 若无需限制发送时长可删除此二行
509 | */
510 | socketClient.getSocketPacketHelper().setSendTimeout(30 * 1000); // 设置发送超时时长,单位毫秒
511 | socketClient.getSocketPacketHelper().setSendTimeoutEnabled(true); // 设置允许使用发送超时时长,此值默认为false
512 | }
513 |
514 | private void __i__setupReadManuallyForReceiver(SocketClient socketClient) {
515 | /**
516 | * 设置读取策略为手动读取
517 | * 手动读取有两种方法
518 | * 1. {@link SocketClient#readDataToData(byte[], boolean)} )} 读取到与指定字节相同的字节序列后回调数据包
519 | * 2. {@link SocketClient#readDataToLength(int)} 读取指定长度的字节后回调数据包
520 | *
521 | * 此时SocketPacketHelper中其他读取相关设置将会无效化
522 | */
523 | socketClient.getSocketPacketHelper().setReadStrategy(SocketPacketHelper.ReadStrategy.Manually);
524 | }
525 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/vilyever/androidsocketclient/TestServer.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.androidsocketclient;
2 |
3 | import android.os.AsyncTask;
4 | import android.support.annotation.NonNull;
5 | import android.widget.Toast;
6 |
7 | import com.vilyever.contextholder.ContextHolder;
8 | import com.vilyever.logger.Logger;
9 | import com.vilyever.socketclient.SocketClient;
10 | import com.vilyever.socketclient.helper.SocketClientDelegate;
11 | import com.vilyever.socketclient.helper.SocketClientReceivingDelegate;
12 | import com.vilyever.socketclient.helper.SocketClientSendingDelegate;
13 | import com.vilyever.socketclient.helper.SocketHeartBeatHelper;
14 | import com.vilyever.socketclient.helper.SocketPacket;
15 | import com.vilyever.socketclient.helper.SocketPacketHelper;
16 | import com.vilyever.socketclient.helper.SocketResponsePacket;
17 | import com.vilyever.socketclient.server.SocketServer;
18 | import com.vilyever.socketclient.server.SocketServerClient;
19 | import com.vilyever.socketclient.server.SocketServerDelegate;
20 | import com.vilyever.socketclient.util.CharsetUtil;
21 |
22 | import java.text.SimpleDateFormat;
23 | import java.util.Arrays;
24 | import java.util.Date;
25 |
26 | /**
27 | * TestServer
28 | * Created by vilyever on 2016/7/26.
29 | * Feature:
30 | */
31 | public class TestServer {
32 | final TestServer self = this;
33 |
34 |
35 | /* Constructors */
36 | public TestServer() {
37 |
38 | }
39 |
40 | /* Public Methods */
41 | public void beginListen() {
42 | int port = getSocketServer().beginListenFromPort(21998);
43 | Toast.makeText(ContextHolder.getContext(), "port " + port, Toast.LENGTH_LONG).show();
44 | }
45 |
46 | /* Properties */
47 | private SocketServer socketServer;
48 | protected SocketServer getSocketServer() {
49 | if (this.socketServer == null) {
50 | this.socketServer = new SocketServer();
51 |
52 | __i__setupEncoding(this.socketServer);
53 |
54 | __i__setupConstantHeartBeat(this.socketServer);
55 |
56 | // __i__setupVariableHeartBeat(this.socketServer);
57 |
58 | // __i__setupReadToTrailerForSender(this.socketServer);
59 | // __i__setupReadToTrailerForReceiver(this.socketServer);
60 |
61 | __i__setupReadByLengthForSender(this.socketServer);
62 | __i__setupReadByLengthForReceiver(this.socketServer);
63 |
64 | // __i__setupReadManuallyForSender(this.socketServer);
65 | // __i__setupReadManuallyForReceiver(this.socketServer);
66 |
67 | this.socketServer.registerSocketServerDelegate(new SocketServerDelegate() {
68 | @Override
69 | public void onServerBeginListen(SocketServer socketServer, int port) {
70 | Logger.log("onServer", "SocketServer: begin listen " + port);
71 |
72 | getTestClient().connect();
73 | }
74 |
75 | @Override
76 | public void onServerStopListen(SocketServer socketServer, int port) {
77 | Logger.log("onServer", "SocketServer: stop listen " + port);
78 | }
79 |
80 | @Override
81 | public void onClientConnected(SocketServer socketServer, SocketServerClient socketServerClient) {
82 | Logger.log("onServer", "SocketServer: onClientConnected");
83 |
84 | self.setServerListeningSocketServerClient(socketServerClient);
85 | socketServerClient.sendString("Server accepted");
86 | }
87 |
88 | @Override
89 | public void onClientDisconnected(SocketServer socketServer, SocketServerClient socketServerClient) {
90 | Logger.log("onServer", "SocketServer: onClientDisconnected");
91 |
92 | self.setServerListeningSocketServerClient(null);
93 | }
94 | });
95 | }
96 | return this.socketServer;
97 | }
98 |
99 | private SocketServerClient serverListeningSocketServerClient;
100 | protected TestServer setServerListeningSocketServerClient(SocketServerClient serverListeningSocketServerClient) {
101 | this.serverListeningSocketServerClient = serverListeningSocketServerClient;
102 | if (serverListeningSocketServerClient == null) {
103 | return this;
104 | }
105 |
106 | this.serverListeningSocketServerClient.registerSocketClientDelegate(new SocketClientDelegate() {
107 | @Override
108 | public void onConnected(SocketClient client) {
109 | Logger.log("onConnected", "SocketServerClient: onConnected");
110 | /**
111 | * 此处永不回调
112 | * 在{@link SocketServerDelegate#onClientConnected(SocketServer, SocketServerClient)} 处处理新client接入时的操作
113 | */
114 | }
115 |
116 | @Override
117 | public void onDisconnected(SocketClient client) {
118 | Logger.log("onDisconnected", "SocketServerClient: onDisconnected");
119 | }
120 |
121 | @Override
122 | public void onResponse(final SocketClient client, @NonNull SocketResponsePacket responsePacket) {
123 | Logger.log("onResponse", "SocketServerClient: onResponse: " + responsePacket.hashCode() + " 【" + responsePacket.getMessage() + "】 " + " isHeartBeat: " + responsePacket.isHeartBeat() + " " + Arrays.toString(responsePacket.getData()));
124 | if (responsePacket.isHeartBeat()) {
125 | return;
126 | }
127 | new AsyncTask() {
128 | @Override
129 | protected Void doInBackground(Void... params) {
130 | try {
131 | Thread.sleep(3 * 1000);
132 | }
133 | catch (InterruptedException e) {
134 | e.printStackTrace();
135 | }
136 |
137 | client.sendString("server on " + System.currentTimeMillis());
138 |
139 | return null;
140 | }
141 |
142 | @Override
143 | protected void onPostExecute(Void aVoid) {
144 | super.onPostExecute(aVoid);
145 |
146 | }
147 | }.execute();
148 | }
149 | });
150 | this.serverListeningSocketServerClient.registerSocketClientSendingDelegate(new SocketClientSendingDelegate() {
151 |
152 | @Override
153 | public void onSendPacketBegin(SocketClient client, SocketPacket packet) {
154 | Logger.log("onSend", "SocketServerClient: onSendPacketBegin: " + packet.hashCode() + " " + Arrays.toString(packet.getData()));
155 | }
156 |
157 | @Override
158 | public void onSendPacketCancel(SocketClient client, SocketPacket packet) {
159 | Logger.log("onSend", "SocketServerClient: onSendPacketCancel: " + packet.hashCode());
160 | }
161 |
162 | @Override
163 | public void onSendingPacketInProgress(SocketClient client, SocketPacket packet, float progress, int sendedLength) {
164 | Logger.log("onSend", "SocketServerClient: onSendingPacketInProgress: " + packet.hashCode() + " : " + progress + " : " + sendedLength);
165 | }
166 |
167 | @Override
168 | public void onSendPacketEnd(SocketClient client, SocketPacket packet) {
169 | Logger.log("onSend", "SocketServerClient: onSendPacketEnd: " + packet.hashCode());
170 | }
171 |
172 | });
173 | this.serverListeningSocketServerClient.registerSocketClientReceiveDelegate(new SocketClientReceivingDelegate() {
174 | @Override
175 | public void onReceivePacketBegin(SocketClient client, SocketResponsePacket packet) {
176 | Logger.log("onReceive", "SocketServerClient: onReceivePacketBegin: " + packet.hashCode());
177 | }
178 |
179 | @Override
180 | public void onReceivePacketEnd(SocketClient client, SocketResponsePacket packet) {
181 | Logger.log("onReceive", "SocketServerClient: onReceivePacketEnd: " + packet.hashCode());
182 | }
183 |
184 | @Override
185 | public void onReceivePacketCancel(SocketClient client, SocketResponsePacket packet) {
186 | Logger.log("onReceive", "SocketServerClient: onReceivePacketCancel: " + packet.hashCode());
187 | }
188 |
189 | @Override
190 | public void onReceivingPacketInProgress(SocketClient client, SocketResponsePacket packet, float progress, int receivedLength) {
191 | Logger.log("onReceive", "SocketServerClient: onReceivingPacketInProgress: " + packet.hashCode() + " : " + progress + " : " + receivedLength);
192 | }
193 | });
194 | return this;
195 | }
196 | protected SocketClient getServerListeningSocketServerClient() {
197 | return this.serverListeningSocketServerClient;
198 | }
199 |
200 | private TestClient testClient;
201 | protected TestClient getTestClient() {
202 | if (this.testClient == null) {
203 | this.testClient = new TestClient();
204 | }
205 | return this.testClient;
206 | }
207 |
208 | /* Overrides */
209 |
210 |
211 | /* Delegates */
212 |
213 |
214 | /* Private Methods */
215 | /**
216 | * 设置自动转换String类型到byte[]类型的编码
217 | * 如未设置(默认为null),将不能使用{@link SocketClient#sendString(String)}发送消息
218 | * 如设置为非null(如UTF-8),在接受消息时会自动尝试在接收线程(非主线程)将接收的byte[]数据依照编码转换为String,在{@link SocketResponsePacket#getMessage()}读取
219 | */
220 | private void __i__setupEncoding(SocketServer socketServer) {
221 | socketServer.setCharsetName(CharsetUtil.UTF_8); // 设置编码为UTF-8
222 | }
223 |
224 | private void __i__setupConstantHeartBeat(SocketServer socketServer) {
225 | /**
226 | * 设置自动发送的心跳包信息
227 | */
228 | socketServer.getHeartBeatHelper().setDefaultSendData(CharsetUtil.stringToData("HeartBeat", CharsetUtil.UTF_8));
229 |
230 | /**
231 | * 设置远程端发送到本地的心跳包信息内容,用于判断接收到的数据包是否是心跳包
232 | * 通过{@link SocketResponsePacket#isHeartBeat()} 查看数据包是否是心跳包
233 | */
234 | socketServer.getHeartBeatHelper().setDefaultReceiveData(CharsetUtil.stringToData("HeartBeat", CharsetUtil.UTF_8));
235 | socketServer.getHeartBeatHelper().setHeartBeatInterval(10 * 1000); // 设置自动发送心跳包的间隔时长,单位毫秒
236 | socketServer.getHeartBeatHelper().setSendHeartBeatEnabled(true); // 设置允许自动发送心跳包,此值默认为false
237 | }
238 |
239 | private void __i__setupVariableHeartBeat(SocketServer socketServer) {
240 | /**
241 | * 设置自动发送的心跳包信息
242 | * 此信息动态生成
243 | *
244 | * 每次发送心跳包时自动调用
245 | */
246 | socketServer.getHeartBeatHelper().setSendDataBuilder(new SocketHeartBeatHelper.SendDataBuilder() {
247 | @Override
248 | public byte[] obtainSendHeartBeatData(SocketHeartBeatHelper helper) {
249 | /**
250 | * 使用当前日期作为心跳包
251 | */
252 | byte[] heartBeatPrefix = new byte[]{0x1F, 0x1F};
253 | byte[] heartBeatSuffix = new byte[]{0x1F, 0x1F};
254 |
255 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
256 | byte[] heartBeatInfo = CharsetUtil.stringToData(sdf.format(new Date()), CharsetUtil.UTF_8);
257 |
258 | byte[] data = new byte[heartBeatPrefix.length + heartBeatSuffix.length + heartBeatInfo.length];
259 | System.arraycopy(heartBeatPrefix, 0, data, 0, heartBeatPrefix.length);
260 | System.arraycopy(heartBeatInfo, 0, data, heartBeatPrefix.length, heartBeatInfo.length);
261 | System.arraycopy(heartBeatSuffix, 0, data, heartBeatPrefix.length + heartBeatInfo.length, heartBeatSuffix.length);
262 |
263 | return data;
264 | }
265 | });
266 |
267 | /**
268 | * 设置远程端发送到本地的心跳包信息的检测器,用于判断接收到的数据包是否是心跳包
269 | * 通过{@link SocketResponsePacket#isHeartBeat()} 查看数据包是否是心跳包
270 | */
271 | socketServer.getHeartBeatHelper().setReceiveHeartBeatPacketChecker(new SocketHeartBeatHelper.ReceiveHeartBeatPacketChecker() {
272 | @Override
273 | public boolean isReceiveHeartBeatPacket(SocketHeartBeatHelper helper, SocketResponsePacket packet) {
274 | /**
275 | * 判断数据包信息是否含有指定的心跳包前缀和后缀
276 | */
277 | byte[] heartBeatPrefix = new byte[]{0x1F, 0x1F};
278 | byte[] heartBeatSuffix = new byte[]{0x1F, 0x1F};
279 |
280 | if (Arrays.equals(heartBeatPrefix, Arrays.copyOfRange(packet.getData(), 0, heartBeatPrefix.length))
281 | && Arrays.equals(heartBeatSuffix, Arrays.copyOfRange(packet.getData(), packet.getData().length - heartBeatSuffix.length, packet.getData().length))) {
282 | return true;
283 | }
284 |
285 | return false;
286 | }
287 | });
288 |
289 | socketServer.getHeartBeatHelper().setHeartBeatInterval(10 * 1000); // 设置自动发送心跳包的间隔时长,单位毫秒
290 | socketServer.getHeartBeatHelper().setSendHeartBeatEnabled(true); // 设置允许自动发送心跳包,此值默认为false
291 | }
292 |
293 | private void __i__setupReadToTrailerForSender(SocketServer socketServer) {
294 | /**
295 | * 根据连接双方协议设置自动发送的包尾数据
296 | * 每次发送数据包(包括心跳包)都会在发送包内容前自动发送此包尾
297 | *
298 | * 例:socketClient.sendData(new byte[]{0x01, 0x02})的步骤为
299 | * 1. socketClient向远程端发送包头(如果设置了包头信息)
300 | * 2. socketClient向远程端发送正文数据{0x01, 0x02}
301 | * 3. socketClient向远程端发送包尾
302 | *
303 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadToTrailer}必须设置此项
304 | * 用于分隔多条消息
305 | */
306 | socketServer.getSocketPacketHelper().setSendTrailerData(new byte[]{0x13, 0x10});
307 |
308 | /**
309 | * 根据连接双方协议设置自动发送的包头数据
310 | * 每次发送数据包(包括心跳包)都会在发送包内容前自动发送此包头
311 | *
312 | * 若无需包头可删除此行
313 | */
314 | socketServer.getSocketPacketHelper().setSendHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));
315 |
316 | /**
317 | * 设置分段发送数据长度
318 | * 即在发送指定长度后通过 {@link SocketClientSendingDelegate#onSendingPacketInProgress(SocketClient, SocketPacket, float, int)}回调当前发送进度
319 | * 注意:无论设置的分段长度为多小,回调的频率最高为1秒30次,防止因此产生主线程的卡顿
320 | *
321 | * 若无需进度回调可删除此二行,删除后仍有【发送开始】【发送结束】的回调
322 | */
323 | socketServer.getSocketPacketHelper().setSendSegmentLength(8); // 设置发送分段长度,单位byte
324 | socketServer.getSocketPacketHelper().setSendSegmentEnabled(true); // 设置允许使用分段发送,此值默认为false
325 |
326 | /**
327 | * 设置发送超时时长
328 | * 在发送每个数据包时,发送每段数据的最长时间,超过后自动断开socket连接
329 | * 通过设置分段发送{@link SocketPacketHelper#setSendSegmentEnabled(boolean)} 可避免发送大数据包时因超时断开,
330 | *
331 | * 若无需限制发送时长可删除此二行
332 | */
333 | socketServer.getSocketPacketHelper().setSendTimeout(30 * 1000); // 设置发送超时时长,单位毫秒
334 | socketServer.getSocketPacketHelper().setSendTimeoutEnabled(true); // 设置允许使用发送超时时长,此值默认为false
335 | }
336 |
337 | private void __i__setupReadToTrailerForReceiver(SocketServer socketServer) {
338 | /**
339 | * 设置读取策略为自动读取到指定的包尾
340 | */
341 | socketServer.getSocketPacketHelper().setReadStrategy(SocketPacketHelper.ReadStrategy.AutoReadToTrailer);
342 |
343 | /**
344 | * 根据连接双方协议设置的包尾数据
345 | * 每次接收数据包(包括心跳包)都会在检测接收到与包尾数据相同的byte[]时回调一个数据包
346 | *
347 | * 例:自动接收远程端所发送的socketClient.sendData(new byte[]{0x01, 0x02})【{0x01, 0x02}为将要接收的数据】的步骤为
348 | * 1. socketClient接收包头(如果设置了包头信息)(接收方式为一直读取到与包头相同的byte[],即可能过滤掉包头前的多余信息)
349 | * 2. socketClient接收正文和包尾(接收方式为一直读取到与尾相同的byte[])
350 | * 3. socketClient回调数据包
351 | *
352 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadToTrailer}必须设置此项
353 | * 用于分隔多条消息
354 | */
355 | socketServer.getSocketPacketHelper().setReceiveTrailerData(new byte[]{0x13, 0x10});
356 |
357 | /**
358 | * 根据连接双方协议设置的包头数据
359 | * 每次接收数据包(包括心跳包)都会在先接收此包头
360 | *
361 | * 若无需包头可删除此行
362 | */
363 | socketServer.getSocketPacketHelper().setReceiveHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));
364 |
365 | /**
366 | * 设置接收超时时长
367 | * 在指定时长内没有数据到达本地自动断开
368 | *
369 | * 若无需限制接收时长可删除此二行
370 | */
371 | socketServer.getSocketPacketHelper().setReceiveTimeout(120 * 1000); // 设置接收超时时长,单位毫秒
372 | socketServer.getSocketPacketHelper().setReceiveTimeoutEnabled(true); // 设置允许使用接收超时时长,此值默认为false
373 | }
374 |
375 | private void __i__setupReadByLengthForSender(SocketServer socketServer) {
376 | /**
377 | * 设置包长度转换器
378 | * 即每次发送数据时,将包头以外的数据长度转换为特定的byte[]发送个远程端用于解析还需要读取多少长度的数据
379 | *
380 | * 例:socketClient.sendData(new byte[]{0x01, 0x02})的步骤为
381 | * 1. socketClient向远程端发送包头(如果设置了包头信息)
382 | * 2. socketClient要发送的数据为{0x01, 0x02},长度为2(若设置了包尾,还需加上包尾的字节长度),通过此转换器将int类型的2转换为4字节的byte[],远程端也照此算法将4字节的byte[]转换为int值
383 | * 3. socketClient向远程端发送转换后的长度信息byte[]
384 | * 4. socketClient向远程端发送正文数据{0x01, 0x02}
385 | * 5. socketClient向远程端发送包尾(如果设置了包尾信息)
386 | *
387 | * 此转换器用于第二步
388 | *
389 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadByLength}必须设置此项
390 | * 用于分隔多条消息
391 | */
392 | socketServer.getSocketPacketHelper().setSendPacketLengthDataConvertor(new SocketPacketHelper.SendPacketLengthDataConvertor() {
393 | @Override
394 | public byte[] obtainSendPacketLengthDataForPacketLength(SocketPacketHelper helper, int packetLength) {
395 | /**
396 | * 简单将int转换为byte[]
397 | */
398 | byte[] data = new byte[4];
399 | data[3] = (byte) (packetLength & 0xFF);
400 | data[2] = (byte) ((packetLength >> 8) & 0xFF);
401 | data[1] = (byte) ((packetLength >> 16) & 0xFF);
402 | data[0] = (byte) ((packetLength >> 24) & 0xFF);
403 | return data;
404 | }
405 | });
406 |
407 | /**
408 | * 根据连接双方协议设置自动发送的包头数据
409 | * 每次发送数据包(包括心跳包)都会在发送包内容前自动发送此包头
410 | *
411 | * 若无需包头可删除此行
412 | */
413 | socketServer.getSocketPacketHelper().setSendHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));
414 |
415 | /**
416 | * 根据连接双方协议设置自动发送的包尾数据
417 | * 每次发送数据包(包括心跳包)都会在发送包内容前自动发送此包尾
418 | *
419 | * 若无需包尾可删除此行
420 | * 注意:
421 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadByLength}时不依赖包尾读取数据
422 | */
423 | socketServer.getSocketPacketHelper().setSendTrailerData(new byte[]{0x13, 0x10});
424 |
425 | /**
426 | * 设置分段发送数据长度
427 | * 即在发送指定长度后通过 {@link SocketClientSendingDelegate#onSendingPacketInProgress(SocketClient, SocketPacket, float, int)}回调当前发送进度
428 | * 注意:无论设置的分段长度为多小,回调的频率最高为1秒30次,防止因此产生主线程的卡顿
429 | *
430 | * 若无需进度回调可删除此二行,删除后仍有【发送开始】【发送结束】的回调
431 | */
432 | socketServer.getSocketPacketHelper().setSendSegmentLength(8); // 设置发送分段长度,单位byte
433 | socketServer.getSocketPacketHelper().setSendSegmentEnabled(true); // 设置允许使用分段发送,此值默认为false
434 |
435 | /**
436 | * 设置发送超时时长
437 | * 在发送每个数据包时,发送每段数据的最长时间,超过后自动断开socket连接
438 | * 通过设置分段发送{@link SocketPacketHelper#setSendSegmentEnabled(boolean)} 可避免发送大数据包时因超时断开,
439 | *
440 | * 若无需限制发送时长可删除此二行
441 | */
442 | socketServer.getSocketPacketHelper().setSendTimeout(30 * 1000); // 设置发送超时时长,单位毫秒
443 | socketServer.getSocketPacketHelper().setSendTimeoutEnabled(true); // 设置允许使用发送超时时长,此值默认为false
444 | }
445 |
446 | private void __i__setupReadByLengthForReceiver(SocketServer socketServer) {
447 | /**
448 | * 设置读取策略为自动读取指定长度
449 | */
450 | socketServer.getSocketPacketHelper().setReadStrategy(SocketPacketHelper.ReadStrategy.AutoReadByLength);
451 |
452 | /**
453 | * 设置包长度转换器
454 | * 即每次接收数据时,将远程端发送到本地的长度信息byte[]转换为int,然后读取相应长度的值
455 | *
456 | * 例:自动接收远程端所发送的socketClient.sendData(new byte[]{0x01, 0x02})【{0x01, 0x02}为将要接收的数据】的步骤为
457 | * 1. socketClient接收包头(如果设置了包头信息)(接收方式为一直读取到与包头相同的byte[],即可能过滤掉包头前的多余信息)
458 | * 2. socketClient接收长度为{@link SocketPacketHelper#getReceivePacketLengthDataLength()}(此处设置为4)的byte[],通过下面设置的转换器,将byte[]转换为int值,此int值暂时称为X
459 | * 3. socketClient接收长度为X的byte[]
460 | * 4. socketClient接收包尾(如果设置了包尾信息)(接收方式为一直读取到与包尾相同的byte[],如无意外情况,此处不会读取到多余的信息)
461 | * 5. socketClient回调数据包
462 | *
463 | * 此转换器用于第二步
464 | *
465 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadByLength}必须设置此项
466 | * 用于分隔多条消息
467 | */
468 | socketServer.getSocketPacketHelper().setReceivePacketLengthDataLength(4);
469 | socketServer.getSocketPacketHelper().setReceivePacketDataLengthConvertor(new SocketPacketHelper.ReceivePacketDataLengthConvertor() {
470 | @Override
471 | public int obtainReceivePacketDataLength(SocketPacketHelper helper, byte[] packetLengthData) {
472 | /**
473 | * 简单将byte[]转换为int
474 | */
475 | int length = (packetLengthData[3] & 0xFF) + ((packetLengthData[2] & 0xFF) << 8) + ((packetLengthData[1] & 0xFF) << 16) + ((packetLengthData[0] & 0xFF) << 24);
476 |
477 | return length;
478 | }
479 | });
480 |
481 | /**
482 | * 根据连接双方协议设置的包头数据
483 | * 每次接收数据包(包括心跳包)都会在先接收此包头
484 | *
485 | * 若无需包头可删除此行
486 | */
487 | socketServer.getSocketPacketHelper().setReceiveHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));
488 |
489 | /**
490 | * 根据连接双方协议设置的包尾数据
491 | * 每次接收数据包(包括心跳包)都会在检测接收到与包尾数据相同的byte[]时回调一个数据包
492 | *
493 | * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadToTrailer}必须设置此项
494 | * 用于分隔多条消息
495 | */
496 | socketServer.getSocketPacketHelper().setReceiveTrailerData(new byte[]{0x13, 0x10});
497 |
498 | /**
499 | * 设置接收超时时长
500 | * 在指定时长内没有数据到达本地自动断开
501 | *
502 | * 若无需限制接收时长可删除此二行
503 | */
504 | socketServer.getSocketPacketHelper().setReceiveTimeout(120 * 1000); // 设置接收超时时长,单位毫秒
505 | socketServer.getSocketPacketHelper().setReceiveTimeoutEnabled(true); // 设置允许使用接收超时时长,此值默认为false
506 | }
507 |
508 | private void __i__setupReadManuallyForSender(SocketServer socketServer) {
509 | /**
510 | * 设置分段发送数据长度
511 | * 即在发送指定长度后通过 {@link SocketClientSendingDelegate#onSendingPacketInProgress(SocketClient, SocketPacket, float, int)}回调当前发送进度
512 | * 注意:无论设置的分段长度为多小,回调的频率最高为1秒30次,防止因此产生主线程的卡顿
513 | *
514 | * 若无需进度回调可删除此二行,删除后仍有【发送开始】【发送结束】的回调
515 | */
516 | socketServer.getSocketPacketHelper().setSendSegmentLength(8); // 设置发送分段长度,单位byte
517 | socketServer.getSocketPacketHelper().setSendSegmentEnabled(true); // 设置允许使用分段发送,此值默认为false
518 |
519 | /**
520 | * 设置发送超时时长
521 | * 在发送每个数据包时,发送每段数据的最长时间,超过后自动断开socket连接
522 | * 通过设置分段发送{@link SocketPacketHelper#setSendSegmentEnabled(boolean)} 可避免发送大数据包时因超时断开,
523 | *
524 | * 若无需限制发送时长可删除此二行
525 | */
526 | socketServer.getSocketPacketHelper().setSendTimeout(30 * 1000); // 设置发送超时时长,单位毫秒
527 | socketServer.getSocketPacketHelper().setSendTimeoutEnabled(true); // 设置允许使用发送超时时长,此值默认为false
528 | }
529 |
530 | private void __i__setupReadManuallyForReceiver(SocketServer socketServer) {
531 | /**
532 | * 设置读取策略为手动读取
533 | * 手动读取有两种方法
534 | * 1. {@link SocketClient#readDataToData(byte[], boolean)} )} 读取到与指定字节相同的字节序列后回调数据包
535 | * 2. {@link SocketClient#readDataToLength(int)} 读取指定长度的字节后回调数据包
536 | *
537 | * 此时SocketPacketHelper中其他读取相关设置将会无效化
538 | */
539 | socketServer.getSocketPacketHelper().setReadStrategy(SocketPacketHelper.ReadStrategy.Manually);
540 | }
541 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
10 |
11 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vilyever/AndroidSocketClient/a93613154993bcd9f7dbeb1e9ea19cc5ccfd7d73/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vilyever/AndroidSocketClient/a93613154993bcd9f7dbeb1e9ea19cc5ccfd7d73/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vilyever/AndroidSocketClient/a93613154993bcd9f7dbeb1e9ea19cc5ccfd7d73/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vilyever/AndroidSocketClient/a93613154993bcd9f7dbeb1e9ea19cc5ccfd7d73/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AndroidSocketClient
3 |
4 | Hello world!
5 | Settings
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.1.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | maven { url "https://jitpack.io" }
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | ## Project-wide Gradle settings.
2 | #
3 | # For more details on how to configure your build environment visit
4 | # http://www.gradle.org/docs/current/userguide/build_environment.html
5 | #
6 | # Specifies the JVM arguments used for the daemon process.
7 | # The setting is particularly useful for tweaking memory settings.
8 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
10 | #
11 | # When configured, Gradle will run in incubating parallel mode.
12 | # This option should only be used with decoupled projects. More details, visit
13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
14 | # org.gradle.parallel=true
15 | #Fri Dec 11 13:43:13 CST 2015
16 | systemProp.http.proxyHost=127.0.0.1
17 | systemProp.http.nonProxyHosts=192.168.*
18 | systemProp.http.proxyPort=1080
19 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vilyever/AndroidSocketClient/a93613154993bcd9f7dbeb1e9ea19cc5ccfd7d73/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Aug 18 13:33:11 CST 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':socketclient'
2 |
--------------------------------------------------------------------------------
/socketclient/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/socketclient/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply from: 'build_library_ext.gradle'
3 |
4 | android {
5 | compileSdkVersion 23
6 | buildToolsVersion "23.0.2"
7 |
8 | defaultConfig {
9 | minSdkVersion 16
10 | targetSdkVersion 23
11 | }
12 | buildTypes {
13 | release {
14 | minifyEnabled false
15 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
16 | }
17 | }
18 | }
19 |
20 | dependencies {
21 | compile fileTree(dir: 'libs', include: ['*.jar'])
22 | compile 'com.android.support:appcompat-v7:23.1.1'
23 |
24 | compile 'com.github.vilyever:AndroidResource:1.2.0'
25 | }
--------------------------------------------------------------------------------
/socketclient/build_library_ext.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | buildVersionName = {
3 | "3.0.3"
4 | }
5 |
6 | /**
7 | * Builds an Android version code from the version of the project.
8 | * This is designed to handle the -SNAPSHOT and -RC format.
9 | *
10 | * I.e. during development the version ends with -SNAPSHOT. As the code stabilizes and release nears
11 | * one or many Release Candidates are tagged. These all end with "-RC1", "-RC2" etc.
12 | * And the final release is without any suffix.
13 | * @return
14 | */
15 | buildVersionCode = {
16 | //The rules is as follows:
17 | //-SNAPSHOT counts as 0
18 | //-RC* counts as the RC number, i.e. 1 to 98
19 | //final release counts as 99.
20 | //Thus you can only have 98 Release Candidates, which ought to be enough for everyone
21 |
22 | def candidate = "0"
23 | def (major, minor, patch) = buildVersionName().toLowerCase().replaceAll('-', '').tokenize('.')
24 | if (patch.endsWith("snapshot")) {
25 | candidate = "0"
26 | patch = patch.replaceAll("[^0-9]","")
27 | } else {
28 | def rc
29 | (patch, rc) = patch.tokenize("rc")
30 | if (rc) {
31 | candidate = rc
32 | }
33 | }
34 |
35 | (major, minor, patch, candidate) = [major, minor, patch, candidate].collect{it.toInteger()}
36 |
37 | (major * 1000 * 1000 * 1000) + (minor * 1000 * 1000) + (patch * 1000) + candidate;
38 | }
39 | }
40 |
41 | android {
42 | defaultConfig {
43 | versionCode buildVersionCode()
44 | versionName buildVersionName()
45 | }
46 | }
47 |
48 | apply plugin: 'com.github.dcendents.android-maven'
49 |
50 | group = 'com.github.vilyever'
51 | version = buildVersionName()
52 |
53 |
54 | // build a jar with source files
55 | task sourceJar(type: Jar) {
56 | from android.sourceSets.main.java.srcDirs
57 | classifier = 'sources'
58 | }
59 |
60 | artifacts {
61 | archives sourceJar
62 | }
63 |
64 | configurations {
65 | published
66 | }
67 |
68 | configure(install.repositories.mavenInstaller) {
69 | pom.project {
70 | licenses {
71 | license {
72 | name 'The Apache Software License, Version 2.0'
73 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
74 | distribution 'repo'
75 | }
76 | }
77 | }
78 | }
--------------------------------------------------------------------------------
/socketclient/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\Development\Android\Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/socketclient/socketclient.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | generateDebugSources
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/socketclient/src/androidTest/java/com/vilyever/socketclient/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/socketclient/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/helper/SocketClientAddress.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.helper;
2 |
3 | import com.vilyever.socketclient.util.StringValidation;
4 |
5 | import java.net.InetSocketAddress;
6 |
7 | /**
8 | * SocketClientAddress
9 | * Created by vilyever on 2016/5/31.
10 | * Feature:
11 | */
12 | public class SocketClientAddress {
13 | final SocketClientAddress self = this;
14 |
15 | public static final int DefaultConnectionTimeout = 1000 * 15;
16 |
17 | /* Constructors */
18 | public SocketClientAddress() {
19 | this(null, null);
20 | }
21 |
22 |
23 | public SocketClientAddress(String remoteIP, int remotePort) {
24 | this(remoteIP, "" + remotePort);
25 | }
26 |
27 | public SocketClientAddress(String remoteIP, int remotePort, int connectionTimeout) {
28 | this(remoteIP, "" + remotePort, connectionTimeout);
29 | }
30 |
31 | public SocketClientAddress(String remoteIP, String remotePort) {
32 | this(remoteIP, remotePort, DefaultConnectionTimeout);
33 | }
34 |
35 | public SocketClientAddress(String remoteIP, String remotePort, int connectionTimeout) {
36 | this.remoteIP = remoteIP;
37 | this.remotePort = remotePort;
38 | this.connectionTimeout = connectionTimeout;
39 | }
40 |
41 | public SocketClientAddress copy() {
42 | SocketClientAddress address = new SocketClientAddress(getRemoteIP(), getRemotePort(), getConnectionTimeout());
43 | address.setOriginal(this);
44 | return address;
45 | }
46 |
47 | /* Public Methods */
48 | public void checkValidation() {
49 | if (!StringValidation.validateRegex(getRemoteIP(), StringValidation.RegexIP)) {
50 | throw new IllegalArgumentException("we need a correct remote IP to connect. Current is " + getRemoteIP());
51 | }
52 |
53 | if (!StringValidation.validateRegex(getRemotePort(), StringValidation.RegexPort)) {
54 | throw new IllegalArgumentException("we need a correct remote port to connect. Current is " + getRemotePort());
55 | }
56 |
57 | if (getConnectionTimeout() < 0) {
58 | throw new IllegalArgumentException("we need connectionTimeout > 0. Current is " + getConnectionTimeout());
59 | }
60 | }
61 |
62 | public SocketClientAddress setRemotePortWithInteger(int port) {
63 | setRemotePort("" + port);
64 | return this;
65 | }
66 |
67 | public int getRemotePortIntegerValue() {
68 | if (getRemotePort() == null) {
69 | return 0;
70 | }
71 |
72 | return Integer.valueOf(getRemotePort());
73 | }
74 |
75 | public InetSocketAddress getInetSocketAddress() {
76 | return new InetSocketAddress(getRemoteIP(), getRemotePortIntegerValue());
77 | }
78 |
79 | /* Properties */
80 | private SocketClientAddress original;
81 | protected SocketClientAddress setOriginal(SocketClientAddress original) {
82 | this.original = original;
83 | return this;
84 | }
85 | public SocketClientAddress getOriginal() {
86 | if (this.original == null) {
87 | return this;
88 | }
89 | return this.original;
90 | }
91 |
92 | /**
93 | * 远程IP
94 | */
95 | private String remoteIP;
96 | public SocketClientAddress setRemoteIP(String remoteIP) {
97 | this.remoteIP = remoteIP;
98 | return this;
99 | }
100 | public String getRemoteIP() {
101 | return this.remoteIP;
102 | }
103 |
104 | /**
105 | * 远程端口
106 | */
107 | private String remotePort;
108 | public SocketClientAddress setRemotePort(String remotePort) {
109 | this.remotePort = remotePort;
110 | return this;
111 | }
112 | public String getRemotePort() {
113 | return this.remotePort;
114 | }
115 |
116 | /**
117 | * 连接超时时间
118 | */
119 | private int connectionTimeout;
120 | public SocketClientAddress setConnectionTimeout(int connectionTimeout) {
121 | this.connectionTimeout = connectionTimeout;
122 | return this;
123 | }
124 | public int getConnectionTimeout() {
125 | return this.connectionTimeout;
126 | }
127 |
128 |
129 | /* Overrides */
130 |
131 |
132 | /* Delegates */
133 |
134 |
135 | /* Private Methods */
136 |
137 | }
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/helper/SocketClientDelegate.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.helper;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import com.vilyever.socketclient.SocketClient;
6 |
7 | /**
8 | * SocketClientDelegate
9 | * Created by vilyever on 2016/5/30.
10 | * Feature:
11 | */
12 | public interface SocketClientDelegate {
13 | void onConnected(SocketClient client);
14 | void onDisconnected(SocketClient client);
15 | void onResponse(SocketClient client, @NonNull SocketResponsePacket responsePacket);
16 |
17 | class SimpleSocketClientDelegate implements SocketClientDelegate {
18 | @Override
19 | public void onConnected(SocketClient client) {
20 |
21 | }
22 |
23 | @Override
24 | public void onDisconnected(SocketClient client) {
25 |
26 | }
27 |
28 | @Override
29 | public void onResponse(SocketClient client, @NonNull SocketResponsePacket responsePacket) {
30 |
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/helper/SocketClientReceivingDelegate.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.helper;
2 |
3 | import com.vilyever.socketclient.SocketClient;
4 |
5 | /**
6 | * SocketClientReceivingDelegate
7 | * Created by vilyever on 2016/5/30.
8 | * Feature:
9 | */
10 | public interface SocketClientReceivingDelegate {
11 | void onReceivePacketBegin(SocketClient client, SocketResponsePacket packet);
12 | void onReceivePacketEnd(SocketClient client, SocketResponsePacket packet);
13 | void onReceivePacketCancel(SocketClient client, SocketResponsePacket packet);
14 | void onReceivingPacketInProgress(SocketClient client, SocketResponsePacket packet, float progress, int receivedLength);
15 |
16 | class SimpleSocketClientReceiveDelegate implements SocketClientReceivingDelegate {
17 | @Override
18 | public void onReceivePacketBegin(SocketClient client, SocketResponsePacket packet) {
19 |
20 | }
21 |
22 | @Override
23 | public void onReceivePacketEnd(SocketClient client, SocketResponsePacket packet) {
24 |
25 | }
26 |
27 | @Override
28 | public void onReceivePacketCancel(SocketClient client, SocketResponsePacket packet) {
29 |
30 | }
31 |
32 | @Override
33 | public void onReceivingPacketInProgress(SocketClient client, SocketResponsePacket packet, float progress, int receivedLength) {
34 |
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/helper/SocketClientSendingDelegate.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.helper;
2 |
3 | import com.vilyever.socketclient.SocketClient;
4 |
5 | /**
6 | * SocketClientSendingDelegate
7 | * Created by vilyever on 2016/5/30.
8 | * Feature:
9 | */
10 | public interface SocketClientSendingDelegate {
11 | void onSendPacketBegin(SocketClient client, SocketPacket packet);
12 | void onSendPacketEnd(SocketClient client, SocketPacket packet);
13 | void onSendPacketCancel(SocketClient client, SocketPacket packet);
14 |
15 | /**
16 | * 发送进度回调
17 | * @param client
18 | * @param packet 正在发送的packet
19 | * @param progress 0.0f-1.0f
20 | * @param sendedLength 已发送的字节数
21 | */
22 | void onSendingPacketInProgress(SocketClient client, SocketPacket packet, float progress, int sendedLength);
23 |
24 | class SimpleSocketClientSendingDelegate implements SocketClientSendingDelegate {
25 | @Override
26 | public void onSendPacketBegin(SocketClient client, SocketPacket packet) {
27 |
28 | }
29 |
30 | @Override
31 | public void onSendPacketEnd(SocketClient client, SocketPacket packet) {
32 |
33 | }
34 |
35 | @Override
36 | public void onSendPacketCancel(SocketClient client, SocketPacket packet) {
37 |
38 | }
39 |
40 | @Override
41 | public void onSendingPacketInProgress(SocketClient client, SocketPacket packet, float progress, int sendedLength) {
42 |
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/helper/SocketConfigure.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.helper;
2 |
3 | /**
4 | * SocketConfigure
5 | * Created by vilyever on 2016/5/31.
6 | * Feature:
7 | */
8 | public class SocketConfigure {
9 | final SocketConfigure self = this;
10 |
11 |
12 | /* Constructors */
13 |
14 |
15 | /* Public Methods */
16 |
17 |
18 | /* Properties */
19 | private String charsetName;
20 | public SocketConfigure setCharsetName(String charsetName) {
21 | this.charsetName = charsetName;
22 | return this;
23 | }
24 | public String getCharsetName() {
25 | return this.charsetName;
26 | }
27 |
28 | private SocketClientAddress address;
29 | public SocketConfigure setAddress(SocketClientAddress address) {
30 | this.address = address.copy();
31 | return this;
32 | }
33 | public SocketClientAddress getAddress() {
34 | return this.address;
35 | }
36 |
37 | private SocketPacketHelper socketPacketHelper;
38 | public SocketConfigure setSocketPacketHelper(SocketPacketHelper socketPacketHelper) {
39 | this.socketPacketHelper = socketPacketHelper.copy();
40 | return this;
41 | }
42 | public SocketPacketHelper getSocketPacketHelper() {
43 | return this.socketPacketHelper;
44 | }
45 |
46 | private SocketHeartBeatHelper heartBeatHelper;
47 | public SocketConfigure setHeartBeatHelper(SocketHeartBeatHelper heartBeatHelper) {
48 | this.heartBeatHelper = heartBeatHelper.copy();
49 | return this;
50 | }
51 | public SocketHeartBeatHelper getHeartBeatHelper() {
52 | return this.heartBeatHelper;
53 | }
54 |
55 | /* Overrides */
56 |
57 |
58 | /* Delegates */
59 |
60 |
61 | /* Private Methods */
62 |
63 | }
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/helper/SocketHeartBeatHelper.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.helper;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * SocketHeartBeatHelper
7 | * Created by vilyever on 2016/5/19.
8 | * Feature:
9 | */
10 | public class SocketHeartBeatHelper {
11 | final SocketHeartBeatHelper self = this;
12 |
13 | /* Constructors */
14 | public SocketHeartBeatHelper() {
15 | }
16 |
17 | public SocketHeartBeatHelper copy() {
18 | SocketHeartBeatHelper helper = new SocketHeartBeatHelper();
19 | helper.setOriginal(this);
20 |
21 | helper.setDefaultSendData(getDefaultSendData());
22 | helper.setSendDataBuilder(getSendDataBuilder());
23 |
24 | helper.setDefaultReceiveData(getDefaultReceiveData());
25 | helper.setReceiveHeartBeatPacketChecker(getReceiveHeartBeatPacketChecker());
26 |
27 | helper.setHeartBeatInterval(getHeartBeatInterval());
28 | helper.setSendHeartBeatEnabled(isSendHeartBeatEnabled());
29 |
30 | return helper;
31 | }
32 |
33 | /* Public Methods */
34 | public byte[] getSendData() {
35 | if (getSendDataBuilder() != null) {
36 | return getSendDataBuilder().obtainSendHeartBeatData(getOriginal());
37 | }
38 |
39 | return getDefaultSendData();
40 | }
41 |
42 | public boolean isReceiveHeartBeatPacket(SocketResponsePacket packet) {
43 | if (getReceiveHeartBeatPacketChecker() != null) {
44 | return getReceiveHeartBeatPacketChecker().isReceiveHeartBeatPacket(getOriginal(), packet);
45 | }
46 |
47 | if (getDefaultReceiveData() != null) {
48 | return packet.isDataEqual(getDefaultReceiveData());
49 | }
50 |
51 | return false;
52 | }
53 |
54 |
55 | /* Properties */
56 | private SocketHeartBeatHelper original;
57 | protected SocketHeartBeatHelper setOriginal(SocketHeartBeatHelper original) {
58 | this.original = original;
59 | return this;
60 | }
61 | public SocketHeartBeatHelper getOriginal() {
62 | if (this.original == null) {
63 | return this;
64 | }
65 | return this.original;
66 | }
67 |
68 | /**
69 | * 发送心跳包的数据
70 | */
71 | private byte[] defaultSendData;
72 | public SocketHeartBeatHelper setDefaultSendData(byte[] defaultSendData) {
73 | if (defaultSendData != null) {
74 | this.defaultSendData = Arrays.copyOf(defaultSendData, defaultSendData.length);
75 | }
76 | else {
77 | this.defaultSendData = null;
78 | }
79 | return this;
80 | }
81 | public byte[] getDefaultSendData() {
82 | return this.defaultSendData;
83 | }
84 |
85 | private SendDataBuilder sendDataBuilder;
86 | public SocketHeartBeatHelper setSendDataBuilder(SendDataBuilder sendDataBuilder) {
87 | this.sendDataBuilder = sendDataBuilder;
88 | return this;
89 | }
90 | public SendDataBuilder getSendDataBuilder() {
91 | return this.sendDataBuilder;
92 | }
93 | public interface SendDataBuilder {
94 | byte[] obtainSendHeartBeatData(SocketHeartBeatHelper helper);
95 | }
96 |
97 | /**
98 | * 接收心跳包的数据,用于过滤远程心跳包
99 | */
100 | private byte[] defaultReceiveData;
101 | public SocketHeartBeatHelper setDefaultReceiveData(byte[] defaultReceiveData) {
102 | if (defaultReceiveData != null) {
103 | this.defaultReceiveData = Arrays.copyOf(defaultReceiveData, defaultReceiveData.length);
104 | }
105 | else {
106 | this.defaultReceiveData = null;
107 | }
108 | return this;
109 | }
110 | public byte[] getDefaultReceiveData() {
111 | return this.defaultReceiveData;
112 | }
113 |
114 | private ReceiveHeartBeatPacketChecker receiveHeartBeatPacketChecker;
115 | public SocketHeartBeatHelper setReceiveHeartBeatPacketChecker(ReceiveHeartBeatPacketChecker receiveHeartBeatPacketChecker) {
116 | this.receiveHeartBeatPacketChecker = receiveHeartBeatPacketChecker;
117 | return this;
118 | }
119 | public ReceiveHeartBeatPacketChecker getReceiveHeartBeatPacketChecker() {
120 | return this.receiveHeartBeatPacketChecker;
121 | }
122 | public interface ReceiveHeartBeatPacketChecker {
123 | boolean isReceiveHeartBeatPacket(SocketHeartBeatHelper helper, SocketResponsePacket packet);
124 | }
125 |
126 | /**
127 | * 心跳包发送间隔
128 | */
129 | private long heartBeatInterval;
130 | public SocketHeartBeatHelper setHeartBeatInterval(long heartBeatInterval) {
131 | this.heartBeatInterval = heartBeatInterval;
132 | return this;
133 | }
134 | public long getHeartBeatInterval() {
135 | return this.heartBeatInterval;
136 | }
137 |
138 | /**
139 | * 是否发送心跳包
140 | * heartBeatInterval不大于0,返回false
141 | */
142 | private boolean sendHeartBeatEnabled;
143 | public SocketHeartBeatHelper setSendHeartBeatEnabled(boolean sendHeartBeatEnabled) {
144 | this.sendHeartBeatEnabled = sendHeartBeatEnabled;
145 | return this;
146 | }
147 | public boolean isSendHeartBeatEnabled() {
148 | if ((getDefaultSendData() == null
149 | && getSendDataBuilder() == null)
150 | || getHeartBeatInterval() <= 0) {
151 | return false;
152 | }
153 | return this.sendHeartBeatEnabled;
154 | }
155 |
156 | /* Overrides */
157 |
158 |
159 | /* Delegates */
160 |
161 |
162 | /* Private Methods */
163 | }
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/helper/SocketInputReader.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.helper;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.Reader;
6 | import java.util.ArrayList;
7 | import java.util.Iterator;
8 |
9 | /**
10 | * SocketInputReader
11 | * AndroidSocketClient
12 | * Created by vilyever on 2016/4/11.
13 | * Feature:
14 | */
15 | public class SocketInputReader extends Reader {
16 | final SocketInputReader self = this;
17 |
18 | private InputStream inputStream;
19 |
20 | /* Constructors */
21 | public SocketInputReader(InputStream inputStream) {
22 | super(inputStream);
23 | this.inputStream = inputStream;
24 | }
25 |
26 | /* Public Methods */
27 |
28 |
29 | /* Properties */
30 |
31 | /* Overrides */
32 | @Override
33 | public void close() throws IOException {
34 | synchronized (lock) {
35 | if (this.inputStream != null) {
36 | this.inputStream.close();
37 | this.inputStream = null;
38 | }
39 | }
40 | }
41 |
42 | @Override
43 | public int read(char[] buffer, int offset, int count) throws IOException {
44 | throw new IOException("read() is not support for SocketInputReader, try readBytes().");
45 | }
46 |
47 | public byte[] readToLength(int length) throws IOException {
48 | if (length <= 0) {
49 | return null;
50 | }
51 |
52 | synchronized (lock) {
53 | if (!__i__isOpen()) {
54 | throw new IOException("InputStreamReader is closed");
55 | }
56 |
57 | try {
58 | byte[] buffer = new byte[length];
59 | int index = 0;
60 | int readCount = 0;
61 |
62 | do {
63 | readCount = this.inputStream.read(buffer, index, length - index);
64 | index += readCount;
65 | } while (readCount != -1 && index < length);
66 |
67 | if (index != length) {
68 | return null;
69 | }
70 |
71 | return buffer;
72 | }
73 | catch (IOException e) {
74 | return null;
75 | }
76 | }
77 | }
78 |
79 | public byte[] readToData(byte[] data, boolean includeData) throws IOException {
80 | if (data == null
81 | || data.length <= 0) {
82 | return null;
83 | }
84 |
85 | synchronized (lock) {
86 | if (!__i__isOpen()) {
87 | throw new IOException("InputStreamReader is closed");
88 | }
89 |
90 | try {
91 | ArrayList list = new ArrayList<>();
92 | int c;
93 |
94 | int matchIndex = 0;
95 |
96 | while (-1 != (c = this.inputStream.read())) {
97 | list.add((byte) c);
98 | if (c == (0xff & data[matchIndex])) {
99 | matchIndex++;
100 | }
101 | else {
102 | matchIndex = 0;
103 | }
104 |
105 | if (matchIndex == data.length) {
106 | break;
107 | }
108 | }
109 |
110 | if (list.size() == 0) {
111 | return null;
112 | }
113 |
114 | int resultLength = list.size() - (includeData ? 0 : data.length);
115 | byte[] result = new byte[resultLength];
116 | Iterator iterator = list.iterator();
117 | for (int i = 0; i < resultLength; i++) {
118 | result[i] = iterator.next();
119 | }
120 |
121 | return result;
122 | }
123 | catch (IOException e) {
124 | return null;
125 | }
126 | }
127 | }
128 |
129 | @Override
130 | public boolean ready() throws IOException {
131 | synchronized (lock) {
132 | if (this.inputStream == null) {
133 | throw new IOException("InputStreamReader is closed");
134 | }
135 | try {
136 | return this.inputStream.available() > 0;
137 | } catch (IOException e) {
138 | return false;
139 | }
140 | }
141 | }
142 |
143 | /* Delegates */
144 |
145 |
146 | /* Private Methods */
147 | public static void __i__checkOffsetAndCount(int arrayLength, int offset, int count) {
148 | if ((offset | count) < 0 || offset > arrayLength || arrayLength - offset < count) {
149 | throw new ArrayIndexOutOfBoundsException("arrayLength=" + arrayLength + "; offset=" + offset
150 | + "; count=" + count);
151 | }
152 | }
153 |
154 | private boolean __i__isOpen() {
155 | return this.inputStream != null;
156 | }
157 | }
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/helper/SocketPacket.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.helper;
2 |
3 | import com.vilyever.socketclient.util.CharsetUtil;
4 |
5 | import java.util.Arrays;
6 | import java.util.concurrent.atomic.AtomicInteger;
7 |
8 | /**
9 | * SocketPacket
10 | * AndroidSocketClient
11 | * Created by vilyever on 2015/9/15.
12 | * Feature:
13 | */
14 | public class SocketPacket {
15 | private final SocketPacket self = this;
16 |
17 | private static final AtomicInteger IDAtomic = new AtomicInteger();
18 |
19 | /* Constructors */
20 | public SocketPacket(byte[] data) {
21 | this(data, false);
22 | }
23 |
24 | public SocketPacket(byte[] data, boolean isHeartBeat) {
25 | this.ID = IDAtomic.getAndIncrement();
26 | this.data = Arrays.copyOf(data, data.length);
27 | this.heartBeat = isHeartBeat;
28 | }
29 |
30 | public SocketPacket(String message) {
31 | this.ID = IDAtomic.getAndIncrement();
32 | this.message = message;
33 | }
34 |
35 | /* Public Methods */
36 | public void buildDataWithCharsetName(String charsetName) {
37 | if (getMessage() != null) {
38 | this.data = CharsetUtil.stringToData(getMessage(), charsetName);
39 | }
40 | }
41 |
42 | /* Properties */
43 | /**
44 | * ID, unique
45 | */
46 | private final int ID;
47 | public int getID() {
48 | return this.ID;
49 | }
50 |
51 | /**
52 | * bytes data
53 | */
54 | private byte[] data;
55 | public byte[] getData() {
56 | return this.data;
57 | }
58 |
59 | /**
60 | * string data
61 | */
62 | private String message;
63 | public String getMessage() {
64 | return this.message;
65 | }
66 |
67 | private boolean heartBeat;
68 | public boolean isHeartBeat() {
69 | return this.heartBeat;
70 | }
71 |
72 | private byte[] headerData;
73 | public SocketPacket setHeaderData(byte[] headerData) {
74 | this.headerData = headerData;
75 | return this;
76 | }
77 | public byte[] getHeaderData() {
78 | return this.headerData;
79 | }
80 |
81 | private byte[] packetLengthData;
82 | public SocketPacket setPacketLengthData(byte[] packetLengthData) {
83 | this.packetLengthData = packetLengthData;
84 | return this;
85 | }
86 | public byte[] getPacketLengthData() {
87 | return this.packetLengthData;
88 | }
89 |
90 | private byte[] trailerData;
91 | public SocketPacket setTrailerData(byte[] trailerData) {
92 | this.trailerData = trailerData;
93 | return this;
94 | }
95 | public byte[] getTrailerData() {
96 | return this.trailerData;
97 | }
98 | }
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/helper/SocketPacketHelper.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.helper;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * SocketPacketHelper
7 | * Created by vilyever on 2016/5/19.
8 | * Feature:
9 | */
10 | public class SocketPacketHelper {
11 | final SocketPacketHelper self = this;
12 |
13 |
14 | /* Constructors */
15 | public SocketPacketHelper() {
16 | }
17 |
18 | public SocketPacketHelper copy() {
19 | SocketPacketHelper helper = new SocketPacketHelper();
20 | helper.setOriginal(this);
21 |
22 | helper.setSendHeaderData(getSendHeaderData());
23 | helper.setSendPacketLengthDataConvertor(getSendPacketLengthDataConvertor());
24 | helper.setSendTrailerData(getSendTrailerData());
25 | helper.setSendSegmentLength(getSendSegmentLength());
26 | helper.setSendSegmentEnabled(isSendSegmentEnabled());
27 | helper.setSendTimeout(getSendTimeout());
28 | helper.setSendTimeoutEnabled(isSendTimeoutEnabled());
29 |
30 | helper.setReadStrategy(getReadStrategy());
31 |
32 | helper.setReceiveHeaderData(getReceiveHeaderData());
33 | helper.setReceivePacketLengthDataLength(getReceivePacketLengthDataLength());
34 | helper.setReceivePacketDataLengthConvertor(getReceivePacketDataLengthConvertor());
35 | helper.setReceiveTrailerData(getReceiveTrailerData());
36 | helper.setReceiveSegmentLength(getReceiveSegmentLength());
37 | helper.setReceiveSegmentEnabled(isReceiveSegmentEnabled());
38 | helper.setReceiveTimeout(getReceiveTimeout());
39 | helper.setReceiveTimeoutEnabled(isReceiveTimeoutEnabled());
40 |
41 | return helper;
42 | }
43 |
44 | /* Public Methods */
45 | public void checkValidation() {
46 | switch (getReadStrategy()) {
47 | case Manually:
48 | return;
49 | case AutoReadToTrailer:
50 | if (getReceiveTrailerData() == null
51 | || getReceiveTrailerData().length <= 0) {
52 | throw new IllegalArgumentException("we need ReceiveTrailerData for AutoReadToTrailer");
53 | }
54 | return;
55 | case AutoReadByLength:
56 | if (getReceivePacketLengthDataLength() <= 0
57 | || getReceivePacketDataLengthConvertor() == null) {
58 | throw new IllegalArgumentException("we need ReceivePacketLengthDataLength and ReceivePacketDataLengthConvertor for AutoReadByLength");
59 | }
60 | return;
61 | }
62 |
63 | throw new IllegalArgumentException("we need a correct ReadStrategy");
64 | }
65 |
66 | public byte[] getSendPacketLengthData(int packetLength) {
67 | if (getSendPacketLengthDataConvertor() != null) {
68 | return getSendPacketLengthDataConvertor().obtainSendPacketLengthDataForPacketLength(getOriginal(), packetLength);
69 | }
70 |
71 | return null;
72 | }
73 |
74 | public int getReceivePacketDataLength(byte[] packetLengthData) {
75 | if (getReadStrategy() == ReadStrategy.AutoReadByLength) {
76 | if (getReceivePacketDataLengthConvertor() != null) {
77 | return getReceivePacketDataLengthConvertor().obtainReceivePacketDataLength(getOriginal(), packetLengthData);
78 | }
79 | }
80 |
81 | return 0;
82 | }
83 |
84 | /* Properties */
85 | private SocketPacketHelper original;
86 | protected SocketPacketHelper setOriginal(SocketPacketHelper original) {
87 | this.original = original;
88 | return this;
89 | }
90 | public SocketPacketHelper getOriginal() {
91 | if (this.original == null) {
92 | return this;
93 | }
94 | return this.original;
95 | }
96 |
97 | /**
98 | * 发送消息时自动添加的包头
99 | */
100 | private byte[] sendHeaderData;
101 | public SocketPacketHelper setSendHeaderData(byte[] sendHeaderData) {
102 | if (sendHeaderData != null) {
103 | this.sendHeaderData = Arrays.copyOf(sendHeaderData, sendHeaderData.length);
104 | }
105 | else {
106 | this.sendHeaderData = null;
107 | }
108 | return this;
109 | }
110 | public byte[] getSendHeaderData() {
111 | return this.sendHeaderData;
112 | }
113 |
114 | private SendPacketLengthDataConvertor sendPacketLengthDataConvertor;
115 | public SocketPacketHelper setSendPacketLengthDataConvertor(SendPacketLengthDataConvertor sendPacketLengthDataConvertor) {
116 | this.sendPacketLengthDataConvertor = sendPacketLengthDataConvertor;
117 | return this;
118 | }
119 | public SendPacketLengthDataConvertor getSendPacketLengthDataConvertor() {
120 | return this.sendPacketLengthDataConvertor;
121 | }
122 | public interface SendPacketLengthDataConvertor {
123 | byte[] obtainSendPacketLengthDataForPacketLength(SocketPacketHelper helper, int packetLength);
124 | }
125 |
126 | /**
127 | * 发送消息时自动添加的包尾
128 | */
129 | private byte[] sendTrailerData;
130 | public SocketPacketHelper setSendTrailerData(byte[] sendTrailerData) {
131 | if (sendTrailerData != null) {
132 | this.sendTrailerData = Arrays.copyOf(sendTrailerData, sendTrailerData.length);
133 | }
134 | else {
135 | this.sendTrailerData = null;
136 | }
137 | return this;
138 | }
139 | public byte[] getSendTrailerData() {
140 | return this.sendTrailerData;
141 | }
142 |
143 | /**
144 | * 发送消息时分段发送的每段大小
145 | * 分段发送可以回调进度
146 | * 此数值表示每次发送byte的长度
147 | * 不大于0表示不分段
148 | */
149 | private int sendSegmentLength;
150 | public SocketPacketHelper setSendSegmentLength(int sendSegmentLength) {
151 | this.sendSegmentLength = sendSegmentLength;
152 | return this;
153 | }
154 | public int getSendSegmentLength() {
155 | return this.sendSegmentLength;
156 | }
157 |
158 | /**
159 | * 若sendSegmentLength不大于0,返回false
160 | */
161 | private boolean sendSegmentEnabled;
162 | public SocketPacketHelper setSendSegmentEnabled(boolean sendSegmentEnabled) {
163 | this.sendSegmentEnabled = sendSegmentEnabled;
164 | return this;
165 | }
166 | public boolean isSendSegmentEnabled() {
167 | if (getSendSegmentLength() <= 0) {
168 | return false;
169 | }
170 | return this.sendSegmentEnabled;
171 | }
172 |
173 | /**
174 | * 发送超时时长,超过时长无法写出自动断开连接
175 | * 仅在每个发送包开始发送时计时,结束后重置计时
176 | */
177 | private long sendTimeout;
178 | public SocketPacketHelper setSendTimeout(long sendTimeout) {
179 | this.sendTimeout = sendTimeout;
180 | return this;
181 | }
182 | public long getSendTimeout() {
183 | return this.sendTimeout;
184 | }
185 |
186 | private boolean sendTimeoutEnabled;
187 | public SocketPacketHelper setSendTimeoutEnabled(boolean sendTimeoutEnabled) {
188 | this.sendTimeoutEnabled = sendTimeoutEnabled;
189 | return this;
190 | }
191 | public boolean isSendTimeoutEnabled() {
192 | return this.sendTimeoutEnabled;
193 | }
194 |
195 | private ReadStrategy readStrategy = ReadStrategy.Manually;
196 | public SocketPacketHelper setReadStrategy(ReadStrategy readStrategy) {
197 | this.readStrategy = readStrategy;
198 | return this;
199 | }
200 | public ReadStrategy getReadStrategy() {
201 | return this.readStrategy;
202 | }
203 | public enum ReadStrategy {
204 | /**
205 | * 手动读取
206 | * 手动调用{@link com.vilyever.socketclient.SocketClient#readDataToData(byte[])}或{@link com.vilyever.socketclient.SocketClient#readDataToLength(int)}读取
207 | */
208 | Manually,
209 | /**
210 | * 自动读取到包尾
211 | * 需设置包尾相关信息
212 | * 自动读取信息直到读取到与包尾相同的数据后,回调接收包
213 | */
214 | AutoReadToTrailer,
215 | /**
216 | * 自动按长度读取
217 | * 需设置长度相关信息
218 | * 自动读取包长度信息,转换成包长度后读取该长度字节后,回调接收包
219 | */
220 | AutoReadByLength,
221 | }
222 |
223 | /**
224 | * 接收消息时每一条消息的头部信息
225 | * 若不为null,每一条接收消息都必须带有此头部信息,否则将无法读取
226 | */
227 | private byte[] receiveHeaderData;
228 | public SocketPacketHelper setReceiveHeaderData(byte[] receiveHeaderData) {
229 | if (receiveHeaderData != null) {
230 | this.receiveHeaderData = Arrays.copyOf(receiveHeaderData, receiveHeaderData.length);
231 | }
232 | else {
233 | this.receiveHeaderData = null;
234 | }
235 | return this;
236 | }
237 | public byte[] getReceiveHeaderData() {
238 | return this.receiveHeaderData;
239 | }
240 |
241 | /**
242 | * 接收时,包长度data的固定字节数
243 | */
244 | private int receivePacketLengthDataLength;
245 | public SocketPacketHelper setReceivePacketLengthDataLength(int receivePacketLengthDataLength) {
246 | this.receivePacketLengthDataLength = receivePacketLengthDataLength;
247 | return this;
248 | }
249 | public int getReceivePacketLengthDataLength() {
250 | return this.receivePacketLengthDataLength;
251 | }
252 |
253 | private ReceivePacketDataLengthConvertor receivePacketDataLengthConvertor;
254 | public SocketPacketHelper setReceivePacketDataLengthConvertor(ReceivePacketDataLengthConvertor receivePacketDataLengthConvertor) {
255 | this.receivePacketDataLengthConvertor = receivePacketDataLengthConvertor;
256 | return this;
257 | }
258 | public ReceivePacketDataLengthConvertor getReceivePacketDataLengthConvertor() {
259 | return this.receivePacketDataLengthConvertor;
260 | }
261 | public interface ReceivePacketDataLengthConvertor {
262 | int obtainReceivePacketDataLength(SocketPacketHelper helper, byte[] packetLengthData);
263 | }
264 |
265 | /**
266 | * 接收消息时每一条消息的尾部信息
267 | * 若不为null,每一条接收消息都必须带有此尾部信息,否则将与下一次输入流合并
268 | */
269 | private byte[] receiveTrailerData;
270 | public SocketPacketHelper setReceiveTrailerData(byte[] receiveTrailerData) {
271 | if (receiveTrailerData != null) {
272 | this.receiveTrailerData = Arrays.copyOf(receiveTrailerData, receiveTrailerData.length);
273 | }
274 | else {
275 | this.receiveTrailerData = null;
276 | }
277 | return this;
278 | }
279 | public byte[] getReceiveTrailerData() {
280 | return this.receiveTrailerData;
281 | }
282 |
283 | /**
284 | * 分段接收消息,每段长度,仅在按长度读取时有效
285 | * 若设置大于0时,receiveSegmentEnabled自动变更为true,反之亦然
286 | * 设置后可手动变更receiveSegmentEnabled
287 | */
288 | private int receiveSegmentLength;
289 | public SocketPacketHelper setReceiveSegmentLength(int receiveSegmentLength) {
290 | this.receiveSegmentLength = receiveSegmentLength;
291 | return this;
292 | }
293 | public int getReceiveSegmentLength() {
294 | return this.receiveSegmentLength;
295 | }
296 |
297 | /**
298 | * 若receiveSegmentLength不大于0,返回false
299 | */
300 | private boolean receiveSegmentEnabled;
301 | public SocketPacketHelper setReceiveSegmentEnabled(boolean receiveSegmentEnabled) {
302 | this.receiveSegmentEnabled = receiveSegmentEnabled;
303 | return this;
304 | }
305 | public boolean isReceiveSegmentEnabled() {
306 | if (getReceiveSegmentLength() <= 0) {
307 | return false;
308 | }
309 | return this.receiveSegmentEnabled;
310 | }
311 |
312 | /**
313 | * 读取超时时长,超过时长没有读取到任何消息自动断开连接
314 | */
315 | private long receiveTimeout;
316 | public SocketPacketHelper setReceiveTimeout(long receiveTimeout) {
317 | this.receiveTimeout = receiveTimeout;
318 | return this;
319 | }
320 | public long getReceiveTimeout() {
321 | return this.receiveTimeout;
322 | }
323 |
324 | private boolean receiveTimeoutEnabled;
325 | public SocketPacketHelper setReceiveTimeoutEnabled(boolean receiveTimeoutEnabled) {
326 | this.receiveTimeoutEnabled = receiveTimeoutEnabled;
327 | return this;
328 | }
329 | public boolean isReceiveTimeoutEnabled() {
330 | return this.receiveTimeoutEnabled;
331 | }
332 |
333 | /* Overrides */
334 |
335 |
336 | /* Delegates */
337 |
338 |
339 | /* Private Methods */
340 |
341 | }
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/helper/SocketResponsePacket.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.helper;
2 |
3 | import com.vilyever.socketclient.util.CharsetUtil;
4 |
5 | import java.util.Arrays;
6 |
7 | /**
8 | * SocketResponsePacket
9 | * AndroidSocketClient
10 | * Created by vilyever on 2016/4/11.
11 | * Feature:
12 | */
13 | public class SocketResponsePacket {
14 | final SocketResponsePacket self = this;
15 |
16 |
17 | /* Constructors */
18 | public SocketResponsePacket() {
19 | }
20 |
21 |
22 | /* Public Methods */
23 | public boolean isDataEqual(byte[] data) {
24 | return Arrays.equals(getData(), data);
25 | }
26 |
27 | public void buildStringWithCharsetName(String charsetName) {
28 | if (getData() != null) {
29 | setMessage(CharsetUtil.dataToString(getData(), charsetName));
30 | }
31 | }
32 |
33 | /* Properties */
34 | private byte[] data;
35 | public SocketResponsePacket setData(byte[] data) {
36 | this.data = data;
37 | return this;
38 | }
39 | public byte[] getData() {
40 | return this.data;
41 | }
42 |
43 | private String message;
44 | public SocketResponsePacket setMessage(String message) {
45 | this.message = message;
46 | return this;
47 | }
48 | public String getMessage() {
49 | return this.message;
50 | }
51 |
52 | private byte[] headerData;
53 | public SocketResponsePacket setHeaderData(byte[] headerData) {
54 | this.headerData = headerData;
55 | return this;
56 | }
57 | public byte[] getHeaderData() {
58 | return this.headerData;
59 | }
60 |
61 | private byte[] packetLengthData;
62 | public SocketResponsePacket setPacketLengthData(byte[] packetLengthData) {
63 | this.packetLengthData = packetLengthData;
64 | return this;
65 | }
66 | public byte[] getPacketLengthData() {
67 | return this.packetLengthData;
68 | }
69 |
70 | private byte[] trailerData;
71 | public SocketResponsePacket setTrailerData(byte[] trailerData) {
72 | this.trailerData = trailerData;
73 | return this;
74 | }
75 | public byte[] getTrailerData() {
76 | return this.trailerData;
77 | }
78 |
79 | private boolean heartBeat;
80 | public SocketResponsePacket setHeartBeat(boolean heartBeat) {
81 | this.heartBeat = heartBeat;
82 | return this;
83 | }
84 | public boolean isHeartBeat() {
85 | return this.heartBeat;
86 | }
87 |
88 |
89 | /* Overrides */
90 |
91 |
92 | /* Delegates */
93 |
94 |
95 | /* Private Methods */
96 |
97 | }
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/server/SocketServer.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.server;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 | import android.os.Message;
6 | import android.support.annotation.NonNull;
7 | import android.support.annotation.WorkerThread;
8 |
9 | import com.vilyever.socketclient.SocketClient;
10 | import com.vilyever.socketclient.helper.SocketClientAddress;
11 | import com.vilyever.socketclient.helper.SocketClientDelegate;
12 | import com.vilyever.socketclient.helper.SocketConfigure;
13 | import com.vilyever.socketclient.helper.SocketHeartBeatHelper;
14 | import com.vilyever.socketclient.helper.SocketPacketHelper;
15 | import com.vilyever.socketclient.helper.SocketResponsePacket;
16 | import com.vilyever.socketclient.util.IPUtil;
17 | import com.vilyever.socketclient.util.StringValidation;
18 |
19 | import java.io.IOException;
20 | import java.lang.ref.WeakReference;
21 | import java.net.ServerSocket;
22 | import java.net.Socket;
23 | import java.util.ArrayList;
24 |
25 | /**
26 | * SocketServer
27 | * AndroidSocketClient
28 | * Created by vilyever on 2016/3/18.
29 | * Feature:
30 | */
31 | public class SocketServer implements SocketClientDelegate {
32 | final SocketServer self = this;
33 |
34 | public static final int NoPort = -1;
35 | public static final int MaxPort = 65535;
36 |
37 |
38 | /* Constructors */
39 | public SocketServer() {
40 | }
41 |
42 | /* Public Methods */
43 | public boolean beginListen(int port) {
44 | if (isListening()) {
45 | return false;
46 | }
47 |
48 | setPort(port);
49 |
50 | getSocketConfigure().setCharsetName(getCharsetName()).setAddress(new SocketClientAddress(IPUtil.getLocalIPAddress(true), "" + port)).setHeartBeatHelper(getHeartBeatHelper()).setSocketPacketHelper(getSocketPacketHelper());
51 |
52 | if (getRunningServerSocket() == null) {
53 | return false;
54 | }
55 |
56 |
57 | setListening(true);
58 | __i__onSocketServerBeginListen();
59 |
60 | return true;
61 | }
62 |
63 | public int beginListenFromPort(int port) {
64 | if (isListening()) {
65 | return NoPort;
66 | }
67 |
68 | while (port <= MaxPort) {
69 | if (beginListen(port)) {
70 | return port;
71 | }
72 | port++;
73 | }
74 |
75 | return NoPort;
76 | }
77 |
78 | public void stopListen() {
79 | if (isListening()) {
80 | getListenThread().interrupt();
81 | try {
82 | getRunningServerSocket().close();
83 | }
84 | catch (IOException e) {
85 | e.printStackTrace();
86 | }
87 | }
88 | }
89 |
90 | public String getIP() {
91 | return getRunningServerSocket().getLocalSocketAddress().toString().substring(1);
92 | }
93 |
94 | public SocketClientAddress getListeningAddress() {
95 | return getSocketConfigure().getAddress();
96 | }
97 |
98 | /**
99 | * 注册监听回调
100 | * @param delegate 回调接收者
101 | */
102 | public SocketServer registerSocketServerDelegate(SocketServerDelegate delegate) {
103 | if (!getSocketServerDelegates().contains(delegate)) {
104 | getSocketServerDelegates().add(delegate);
105 | }
106 | return this;
107 | }
108 |
109 | /**
110 | * 取消注册监听回调
111 | * @param delegate 回调接收者
112 | */
113 | public SocketServer removeSocketServerDelegate(SocketServerDelegate delegate) {
114 | getSocketServerDelegates().remove(delegate);
115 | return this;
116 | }
117 |
118 | /* Properties */
119 | private ServerSocket runningServerSocket;
120 | protected SocketServer setRunningServerSocket(ServerSocket runningServerSocket) {
121 | this.runningServerSocket = runningServerSocket;
122 | return this;
123 | }
124 | protected ServerSocket getRunningServerSocket() {
125 | if (this.runningServerSocket == null) {
126 | try {
127 | this.runningServerSocket = new ServerSocket(getPort());
128 | }
129 | catch (IOException e) {
130 | e.printStackTrace();
131 | }
132 | }
133 | return this.runningServerSocket;
134 | }
135 |
136 | private int port = NoPort;
137 | public int getPort() {
138 | return this.port;
139 | }
140 | protected SocketServer setPort(int port) {
141 | if (!StringValidation.validateRegex("" + port, StringValidation.RegexPort)) {
142 | throw new IllegalArgumentException("we need a correct remote port to listen");
143 | }
144 |
145 | if (isListening()) {
146 | return this;
147 | }
148 |
149 | this.port = port;
150 | return this;
151 | }
152 |
153 | private boolean listening;
154 | protected SocketServer setListening(boolean listening) {
155 | this.listening = listening;
156 | return this;
157 | }
158 | public boolean isListening() {
159 | return this.listening;
160 | }
161 |
162 | private ListenThread listenThread;
163 | protected SocketServer setListenThread(ListenThread listenThread) {
164 | this.listenThread = listenThread;
165 | return this;
166 | }
167 | protected ListenThread getListenThread() {
168 | if (this.listenThread == null) {
169 | this.listenThread = new ListenThread();
170 | }
171 | return this.listenThread;
172 | }
173 |
174 | /**
175 | * 统一配置默认的编码格式
176 | */
177 | private String charsetName;
178 | public SocketServer setCharsetName(String charsetName) {
179 | this.charsetName = charsetName;
180 | return this;
181 | }
182 | public String getCharsetName() {
183 | return this.charsetName;
184 | }
185 |
186 | private SocketPacketHelper socketPacketHelper;
187 | public SocketServer setSocketPacketHelper(SocketPacketHelper socketPacketHelper) {
188 | this.socketPacketHelper = socketPacketHelper;
189 | return this;
190 | }
191 | public SocketPacketHelper getSocketPacketHelper() {
192 | if (this.socketPacketHelper == null) {
193 | this.socketPacketHelper = new SocketPacketHelper();
194 | }
195 | return this.socketPacketHelper;
196 | }
197 |
198 | private SocketHeartBeatHelper heartBeatHelper;
199 | public SocketServer setHeartBeatHelper(SocketHeartBeatHelper heartBeatHelper) {
200 | this.heartBeatHelper = heartBeatHelper;
201 | return this;
202 | }
203 | public SocketHeartBeatHelper getHeartBeatHelper() {
204 | if (this.heartBeatHelper == null) {
205 | this.heartBeatHelper = new SocketHeartBeatHelper();
206 | }
207 | return this.heartBeatHelper;
208 | }
209 |
210 | private SocketConfigure socketConfigure;
211 | protected SocketConfigure getSocketConfigure() {
212 | if (this.socketConfigure == null) {
213 | this.socketConfigure = new SocketConfigure();
214 | }
215 | return this.socketConfigure;
216 | }
217 |
218 | private ArrayList runningSocketServerClients;
219 | protected ArrayList getRunningSocketServerClients() {
220 | if (this.runningSocketServerClients == null) {
221 | this.runningSocketServerClients = new ArrayList();
222 | }
223 | return this.runningSocketServerClients;
224 | }
225 |
226 | private ArrayList socketServerDelegates;
227 | protected ArrayList getSocketServerDelegates() {
228 | if (this.socketServerDelegates == null) {
229 | this.socketServerDelegates = new ArrayList();
230 | }
231 | return this.socketServerDelegates;
232 | }
233 |
234 | private UIHandler uiHandler;
235 | protected UIHandler getUiHandler() {
236 | if (this.uiHandler == null) {
237 | this.uiHandler = new UIHandler(this);
238 | }
239 | return this.uiHandler;
240 | }
241 | private static class UIHandler extends Handler {
242 | private WeakReference referenceSocketServer;
243 |
244 | public UIHandler(@NonNull SocketServer referenceSocketServer) {
245 | super(Looper.getMainLooper());
246 |
247 | this.referenceSocketServer = new WeakReference(referenceSocketServer);
248 | }
249 |
250 | @Override
251 | public void handleMessage(Message msg) {
252 | super.handleMessage(msg);
253 | }
254 | }
255 |
256 | /* Overrides */
257 |
258 |
259 | /* Delegates */
260 | @Override
261 | public void onConnected(SocketClient client) {
262 |
263 | }
264 |
265 | @Override
266 | public void onDisconnected(SocketClient client) {
267 | getRunningSocketServerClients().remove(client);
268 | __i__onSocketServerClientDisconnected((SocketServerClient) client);
269 | }
270 |
271 | @Override
272 | public void onResponse(SocketClient client, @NonNull SocketResponsePacket responsePacket) {
273 |
274 | }
275 |
276 |
277 | /* Protected Methods */
278 | @WorkerThread
279 | protected SocketServerClient internalGetSocketServerClient(Socket socket) {
280 | return new SocketServerClient(socket, getSocketConfigure());
281 | }
282 |
283 | /* Private Methods */
284 | private boolean __i__checkServerSocketAvailable() {
285 | return getRunningServerSocket() != null && !getRunningServerSocket().isClosed();
286 | }
287 |
288 | private void __i__disconnectAllClients() {
289 | if (Looper.myLooper() != Looper.getMainLooper()) {
290 | getUiHandler().post(new Runnable() {
291 | @Override
292 | public void run() {
293 | self.__i__disconnectAllClients();
294 | }
295 | });
296 | return;
297 | }
298 |
299 | while (getRunningSocketServerClients().size() > 0) {
300 | SocketServerClient client = getRunningSocketServerClients().get(0);
301 | getRunningSocketServerClients().remove(client);
302 | client.disconnect();
303 | }
304 | }
305 |
306 | private void __i__onSocketServerBeginListen() {
307 | if (Looper.myLooper() != Looper.getMainLooper()) {
308 | getUiHandler().post(new Runnable() {
309 | @Override
310 | public void run() {
311 | self.__i__onSocketServerBeginListen();
312 | }
313 | });
314 | return;
315 | }
316 |
317 | ArrayList copyList =
318 | (ArrayList) getSocketServerDelegates().clone();
319 | int count = copyList.size();
320 | for (int i = 0; i < count; ++i) {
321 | copyList.get(i).onServerBeginListen(this, getPort());
322 | }
323 |
324 | getListenThread().start();
325 | }
326 |
327 | private void __i__onSocketServerStopListen() {
328 | if (Looper.myLooper() != Looper.getMainLooper()) {
329 | getUiHandler().post(new Runnable() {
330 | @Override
331 | public void run() {
332 | self.__i__onSocketServerStopListen();
333 | }
334 | });
335 | return;
336 | }
337 |
338 | ArrayList copyList =
339 | (ArrayList) getSocketServerDelegates().clone();
340 | int count = copyList.size();
341 | for (int i = 0; i < count; ++i) {
342 | copyList.get(i).onServerStopListen(this, getPort());
343 | }
344 | }
345 |
346 | private void __i__onSocketServerClientConnected(final SocketServerClient socketServerClient) {
347 | if (Looper.myLooper() != Looper.getMainLooper()) {
348 | getUiHandler().post(new Runnable() {
349 | @Override
350 | public void run() {
351 | self.__i__onSocketServerClientConnected(socketServerClient);
352 | }
353 | });
354 | return;
355 | }
356 |
357 | ArrayList copyList =
358 | (ArrayList) getSocketServerDelegates().clone();
359 | int count = copyList.size();
360 | for (int i = 0; i < count; ++i) {
361 | copyList.get(i).onClientConnected(this, socketServerClient);
362 | }
363 | }
364 |
365 | private void __i__onSocketServerClientDisconnected(final SocketServerClient socketServerClient) {
366 | if (Looper.myLooper() != Looper.getMainLooper()) {
367 | getUiHandler().post(new Runnable() {
368 | @Override
369 | public void run() {
370 | self.__i__onSocketServerClientDisconnected(socketServerClient);
371 | }
372 | });
373 | return;
374 | }
375 |
376 | ArrayList copyList =
377 | (ArrayList) getSocketServerDelegates().clone();
378 | int count = copyList.size();
379 | for (int i = 0; i < count; ++i) {
380 | copyList.get(i).onClientDisconnected(this, socketServerClient);
381 | }
382 | }
383 |
384 | /* Inner Classes */
385 | private class ListenThread extends Thread {
386 | private boolean running;
387 | protected ListenThread setRunning(boolean running) {
388 | this.running = running;
389 | return this;
390 | }
391 | protected boolean isRunning() {
392 | return this.running;
393 | }
394 |
395 | @Override
396 | public void run() {
397 | super.run();
398 | setRunning(true);
399 | while (!Thread.interrupted()
400 | && self.__i__checkServerSocketAvailable()) {
401 | Socket socket = null;
402 | try {
403 | socket = self.getRunningServerSocket().accept();
404 |
405 |
406 | SocketServerClient socketServerClient = self.internalGetSocketServerClient(socket);
407 | getRunningSocketServerClients().add(socketServerClient);
408 | socketServerClient.registerSocketClientDelegate(self);
409 | self.__i__onSocketServerClientConnected(socketServerClient);
410 | }
411 | catch (IOException e) {
412 | // e.printStackTrace();
413 | }
414 | }
415 |
416 | setRunning(false);
417 |
418 | self.setListening(false);
419 | self.setListenThread(null);
420 | self.setRunningServerSocket(null);
421 |
422 | self. __i__disconnectAllClients();
423 | self.__i__onSocketServerStopListen();
424 | }
425 | }
426 | }
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/server/SocketServerClient.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.server;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import com.vilyever.socketclient.SocketClient;
6 | import com.vilyever.socketclient.helper.SocketClientAddress;
7 | import com.vilyever.socketclient.helper.SocketConfigure;
8 |
9 | import java.net.Socket;
10 |
11 | /**
12 | * SocketServerClient
13 | * AndroidSocketClient
14 | * Created by vilyever on 2016/3/23.
15 | * Feature:
16 | */
17 | public class SocketServerClient extends SocketClient {
18 | final SocketServerClient self = this;
19 |
20 |
21 | /* Constructors */
22 | public SocketServerClient(@NonNull Socket socket, SocketConfigure configure) {
23 | super(new SocketClientAddress(socket.getLocalAddress().toString().substring(1), "" + socket.getLocalPort()));
24 |
25 | setRunningSocket(socket);
26 | getSocketConfigure().setCharsetName(configure.getCharsetName()).setAddress(getAddress()).setHeartBeatHelper(configure.getHeartBeatHelper()).setSocketPacketHelper(configure.getSocketPacketHelper());
27 |
28 | internalOnConnected();
29 | }
30 |
31 | /* Public Methods */
32 |
33 |
34 | /* Properties */
35 |
36 |
37 | /* Overrides */
38 |
39 |
40 | /* Delegates */
41 |
42 |
43 | /* Private Methods */
44 |
45 | }
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/server/SocketServerDelegate.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.server;
2 |
3 | /**
4 | * SocketServerDelegate
5 | * Created by vilyever on 2016/5/31.
6 | * Feature:
7 | */
8 | public interface SocketServerDelegate {
9 | void onServerBeginListen(SocketServer socketServer, int port);
10 | void onServerStopListen(SocketServer socketServer, int port);
11 | void onClientConnected(SocketServer socketServer, SocketServerClient socketServerClient);
12 | void onClientDisconnected(SocketServer socketServer, SocketServerClient socketServerClient);
13 |
14 | class SimpleSocketServerDelegate implements SocketServerDelegate {
15 | @Override
16 | public void onServerBeginListen(SocketServer socketServer, int port) {
17 |
18 | }
19 |
20 | @Override
21 | public void onServerStopListen(SocketServer socketServer, int port) {
22 |
23 | }
24 |
25 | @Override
26 | public void onClientConnected(SocketServer socketServer, SocketServerClient socketServerClient) {
27 |
28 | }
29 |
30 | @Override
31 | public void onClientDisconnected(SocketServer socketServer, SocketServerClient socketServerClient) {
32 |
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/util/BytesWrapper.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.util;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * BytesWrapper
7 | * AndroidSocketClient
8 | * Created by vilyever on 2016/4/27.
9 | * Feature:
10 | */
11 | public class BytesWrapper {
12 | final BytesWrapper self = this;
13 |
14 |
15 | /* Constructors */
16 | public BytesWrapper(byte[] bytes) {
17 | if (bytes == null) {
18 | throw new NullPointerException();
19 | }
20 | this.bytes = bytes;
21 | }
22 |
23 | /* Public Methods */
24 | public boolean equalsBytes(byte[] bytes) {
25 | return Arrays.equals(getBytes(), bytes);
26 | }
27 |
28 | /* Properties */
29 | private final byte[] bytes;
30 | public byte[] getBytes() {
31 | return this.bytes;
32 | }
33 |
34 | /* Overrides */
35 | @Override
36 | public boolean equals(Object other)
37 | {
38 | if (!(other instanceof BytesWrapper)) {
39 | return false;
40 | }
41 | return equalsBytes(((BytesWrapper)other).getBytes());
42 | }
43 |
44 | @Override
45 | public int hashCode() {
46 | return Arrays.hashCode(getBytes());
47 | }
48 |
49 | /* Delegates */
50 |
51 |
52 | /* Private Methods */
53 |
54 | }
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/util/CharsetUtil.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.util;
2 |
3 | import java.io.UnsupportedEncodingException;
4 |
5 | /**
6 | * CharsetUtil
7 | * AndroidSocketClient
8 | * Created by vilyever on 2016/4/11.
9 | * Feature:
10 | */
11 | public class CharsetUtil {
12 | final CharsetUtil self = this;
13 |
14 | public static final String UTF_8 = "UTF-8";
15 |
16 | /* Constructors */
17 |
18 |
19 | /* Public Methods */
20 | public static byte[] stringToData(String string, String charsetName) {
21 | if (string != null) {
22 | try {
23 | return string.getBytes(charsetName);
24 | }
25 | catch (UnsupportedEncodingException e) {
26 | e.printStackTrace();
27 | }
28 | }
29 | return null;
30 | }
31 |
32 | public static String dataToString(byte[] data, String charsetName) {
33 | if (data != null) {
34 | try {
35 | return new String(data, charsetName);
36 | }
37 | catch (UnsupportedEncodingException e) {
38 | e.printStackTrace();
39 | }
40 | }
41 | return null;
42 | }
43 |
44 | /* Properties */
45 |
46 |
47 | /* Overrides */
48 |
49 |
50 | /* Delegates */
51 |
52 |
53 | /* Private Methods */
54 |
55 | }
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/util/IPUtil.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.util;
2 |
3 | import java.net.InetAddress;
4 | import java.net.NetworkInterface;
5 | import java.util.Collections;
6 | import java.util.List;
7 |
8 | /**
9 | * IPUtil
10 | * AndroidSocketClient
11 | * Created by vilyever on 2016/3/30.
12 | * Feature:
13 | */
14 | public class IPUtil {
15 | final IPUtil self = this;
16 |
17 |
18 | /* Constructors */
19 |
20 |
21 | /* Public Methods */
22 | public static String getLocalIPAddress(boolean useIPv4) {
23 | try {
24 | List interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
25 | for (NetworkInterface networkInterface : interfaces) {
26 | List inetAddresses = Collections.list(networkInterface.getInetAddresses());
27 | for (InetAddress address : inetAddresses) {
28 | if (!address.isLoopbackAddress()) {
29 | String sAddr = address.getHostAddress();
30 | //boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);
31 | boolean isIPv4 = sAddr.indexOf(':')<0;
32 |
33 | if (useIPv4) {
34 | if (isIPv4)
35 | return sAddr;
36 | } else {
37 | if (!isIPv4) {
38 | int delim = sAddr.indexOf('%'); // drop ip6 zone suffix
39 | return delim<0 ? sAddr.toUpperCase() : sAddr.substring(0, delim).toUpperCase();
40 | }
41 | }
42 | }
43 | }
44 | }
45 | } catch (Exception ex) { } // for now eat exceptions
46 | return "";
47 | }
48 |
49 | /* Properties */
50 |
51 |
52 | /* Overrides */
53 |
54 |
55 | /* Delegates */
56 |
57 |
58 | /* Private Methods */
59 |
60 | }
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/vilyever/socketclient/util/StringValidation.java:
--------------------------------------------------------------------------------
1 | package com.vilyever.socketclient.util;
2 |
3 | /**
4 | * StringValidation
5 | * ESB
6 | * Created by vilyever on 2016/2/23.
7 | * Feature:
8 | * 输入检查
9 | * 正则检查String是否符合某些格式
10 | */
11 | public class StringValidation {
12 | final StringValidation self = this;
13 |
14 | public final static String RegexAllChinese = "^[\\u4e00-\\u9fa5]*$";
15 | public final static String RegexChineseName = "^[\\u4e00-\\u9fa5]{2,15}$"; // According To Statistics, the longest name has 15 character
16 | public final static String RegexPhoneNumber = "^(((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8})|((\\d{3,4}-)?\\d{7,8}(-\\d{1,4})?)$";
17 | public final static String RegexEmail = "w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*";
18 | public final static String RegexIP = "^(25[0-5]|2[0-4][0-9]|1{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\\.(25[0-5]|2[0-4][0-9]|1{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|1{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|1{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$";
19 | public final static String RegexPort = "^6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{0,3}$";
20 |
21 |
22 | /* Constructors */
23 |
24 |
25 | /* Public Methods */
26 | public static boolean validateRegularCharacter(String string, int minSize, int maxSize) {
27 | return validateRegex(string, "^\\w{" + minSize + "," + maxSize + "}$");
28 | }
29 |
30 | public static boolean validateRegex(String string, String regex) {
31 | if (string == null) {
32 | return false;
33 | }
34 |
35 | return string.matches(regex);
36 | }
37 |
38 |
39 | /* Properties */
40 |
41 |
42 | /* Overrides */
43 |
44 |
45 | /* Delegates */
46 |
47 |
48 | /* Private Methods */
49 |
50 | }
--------------------------------------------------------------------------------
/socketclient/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | VDSocketClient
3 |
4 |
--------------------------------------------------------------------------------