(this, android.R.layout.simple_spinner_item, mList);
62 | //设置样式
63 | arr_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
64 | //加载适配器
65 | spMode.setAdapter(arr_adapter);
66 |
67 | Gson gson = new Gson();
68 | TestBean codeGetModel = new TestBean();
69 | codeGetModel.protver = "100";
70 | codeGetModel.pkgtype = 1;
71 | codeGetModel.command = 15;
72 | codeGetModel.seq = 1000;
73 | TestBean.Inform in = codeGetModel.body;
74 | in.cmd = type;
75 | in.Phone = "18500000000";
76 | final String json = gson.toJson(codeGetModel);
77 | // bean转字符串并发送
78 | reDataStr = json + "\r\n";
79 | Log.i(TAG, "reDataStr-->" + reDataStr);
80 | tvRequest.setText(json);
81 | }
82 |
83 | private void initListener() {
84 | spMode.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
85 | @Override
86 | public void onItemSelected(AdapterView> parent, View view, int position, long id) {
87 | String str = mList.get(position).toString().trim();
88 | if (str.equals("auto")) {
89 | Socketer.getInstance(MainActivity.this).setParseMode(ParseMode.AUTO_PARSE);
90 | parseMode = ParseMode.AUTO_PARSE;
91 | } else if (str.equals("manually")) {
92 | Socketer.getInstance(MainActivity.this).setParseMode(ParseMode.MANUALLY_PARSE);
93 | parseMode = ParseMode.MANUALLY_PARSE;
94 | }
95 | }
96 |
97 | @Override
98 | public void onNothingSelected(AdapterView> parent) {
99 | Socketer.getInstance(MainActivity.this).setParseMode(ParseMode.AUTO_PARSE);
100 | parseMode = ParseMode.AUTO_PARSE;
101 | }
102 |
103 | });
104 |
105 | btSend.setOnClickListener(new View.OnClickListener() {
106 | @Override
107 | public void onClick(View v) {
108 | switch (parseMode) {
109 | case AUTO_PARSE:
110 | autoReceiveData();
111 |
112 | break;
113 | case MANUALLY_PARSE:
114 | boolean sendResult = Socketer.getInstance(MainActivity.this).sendStrData(reDataStr);//request
115 | if (!sendResult) {
116 | Toast.makeText(MainActivity.this, "send fail", Toast.LENGTH_SHORT).show();
117 | }
118 |
119 | break;
120 |
121 | default:
122 |
123 | break;
124 | }
125 | }
126 | });
127 | }
128 |
129 |
130 | private void manuallyParseListener() {
131 | Socketer.getInstance(MainActivity.this).setOnReceiveListener(new OnReceiveListener() {
132 | @Override
133 | public void onConnected(Socketer socketer) {
134 | Log.i(TAG, "服务器连接成功");
135 | }
136 |
137 | @Override
138 | public void onDisconnected(Socketer socketer) {
139 | Log.e(TAG, "服务器断开连接");
140 | }
141 |
142 | @Override
143 | public void onResponse(final String data) {
144 | runOnUiThread(new Runnable() {
145 | @Override
146 | public void run() {
147 | //response data
148 | tvResponse.setTextColor(getResources().getColor(R.color.blue));
149 | tvResponse.setText(data);
150 | }
151 | });
152 | }
153 | });
154 | }
155 |
156 | private void autoReceiveData() {
157 | //Socketer.getInstance(MainActivity.this).reConnectSever("192.168.2.171", 20083);
158 | Socketer.getInstance(MainActivity.this).sendStrData(reDataStr, "\"seq\":1000", new ResponseListener() {
159 | @Override
160 | public void onSuccess(final String data) {
161 | Log.i("Test server data", "callback data:" + data);
162 | runOnUiThread(new Runnable() {
163 | @Override
164 | public void run() {
165 | tvResponse.setTextColor(getResources().getColor(R.color.red));
166 | tvResponse.setText(data);
167 | }
168 | });
169 | }
170 |
171 | @Override
172 | public void onFail(final int failCode) {
173 | Log.e("Test server data", "callback error:" + failCode);
174 | runOnUiThread(new Runnable() {
175 | @Override
176 | public void run() {
177 | Toast.makeText(MainActivity.this, "返回错误码:" + failCode, Toast.LENGTH_SHORT).show();
178 | }
179 | });
180 | }
181 | });
182 | }
183 |
184 |
185 | }
186 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AndroidSocket #
2 | A simple Android socket communication, you're gonna love it!
3 | 
4 |
5 | Add AndroidSocket to your project
6 | -----
7 |
8 | #### Gradle
9 | compile 'com.virtue.androidsocket:AndroidSocket:1.0.7'
10 |
11 | #### Maven
12 |
13 | com.virtue.androidsocket
14 | AndroidSocket
15 | 1.0.7
16 | pom
17 |
18 |
19 |
20 |
21 | How do I use AndroidSocket?(使用说明)
22 | -----
23 |
24 | #### First you need to build a service for socket communication and heartbeat tasks before you use it.(在使用之前建一个服务,用于socket通讯, 在服务中可以建立自己的心跳任务)
25 | startService(new Intent(this, MySocketService.class));
26 |
27 |
28 |
29 | #### In the service, configure the relevant parameters.(服务中配置连接参数)
30 | Socketer.getInstance(getApplicationContext()).bindServerConnect("123.57.56.201", 20083) //配置socket地址和端口
31 | .setTimeout(15).setEncode("UTF_8") //Configure Timeout and encoding,Timeout unit is seconds配置超时时间与编码
32 | .setReceiveType(ReceiveType.SEPARATION_SIGN) //Configuring the Receive Type配置接收形式以分隔符接收
33 | .setEndCharSequence("\r\n") //"\r\n" is End for split 配置结束符
34 | .setSendMaxByteLength(1500).start(); //Send Max bytes配置一次性最多发送的消息字节数
35 | 或者or:
36 | Socketer.getInstance(getApplicationContext()).bindServerConnect("123.57.56.201", 20083)
37 | .setTimeout(15).setEncode("UTF_8")
38 | .setReceiveType(ReceiveType.FIXED_LENGTH) //Configuring the Receive Type配置接收形式以分隔符接收
39 | .setMsgLength(2048) //Fixed length receive 配置固定长度大小接收
40 | .setSendMaxByteLength(1500).start(); //配置一次性最多发送的消息字节数
41 |
42 |
43 |
44 |
45 | Case1. Auto Parse ! (自动解析包含服务器主推通知和请求响应两种数据)
46 | -----
47 |
48 | #### If the service has unsolicited information to you, you need to register a broadcast, like this:(如果服务有主推通知消息,你需要注册以下广播)
49 |
50 | //Set parse to Auto
51 | Socketer.getInstance(MainActivity.this).setParseMode(ParseMode.AUTO_PARSE);
52 |
53 | IntentFilter intentFilter = new IntentFilter();
54 | intentFilter.addAction(BroadCastType.SERVER_NOTICE);
55 | MessageReceiver dataReceiver = new MessageReceiver();
56 | registerReceiver(dataReceiver, intentFilter);
57 |
58 |
59 |
60 | #### Broadcast reception is as follows:(广播接收如下)
61 | @Override
62 | public void onReceive(Context context, Intent intent) {
63 | if (intent.getAction().equals(BroadCastType.SERVER_NOTICE)) {
64 | String dataStr = intent.getStringExtra(BroadCastType.SERVER_NOTICE_DATA);
65 | Log.i(TAG, "Data given to me by the server:" + dataStr);
66 | }
67 | }
68 |
69 |
70 |
71 | #### Send a request to the server(发送请求到服务器)
72 | Socketer.getInstance(MainActivity.this).sendStrData(reDataStr, "\"seq\":100", new ResponseListener() {
73 | @Override
74 | public void onSuccess(final String data) {
75 | Log.i("Test server data", "callback data:" + data);
76 | runOnUiThread(new Runnable() {
77 | @Override
78 | public void run() {
79 | tvResponse.setText(data);
80 | }
81 | });
82 | }
83 |
84 | @Override
85 | public void onFail(int failCode) {
86 | Log.e("Test server data", "callback error:" + failCode);
87 | }
88 | });
89 |
90 | 其中参数1代表是请求的数据,参数2代表是返回数据中的唯一标识,可以是请求ID、token值或者能标识唯一性的字符串
91 | Where parameter 1 represents the requested data, parameter 2 represents a unique identity in the returned data, either a request ID, a token value, or a string that uniquely identifies the uniqueness.
92 |
93 |
94 |
95 | Case2. Manually Parse!suggest.(手动解析没有服务主推通知和请求响应之分,完全由自己自定义解析)
96 | ------
97 |
98 | #### If you want to parse the response data yourself(如果想自己解析响应数据)
99 | //Set parse to Manual
100 | Socketer.getInstance(MainActivity.this).setParseMode(ParseMode.MANUALLY_PARSE);
101 |
102 | #### Set Listener for response(设置监听响应)
103 | Socketer.getInstance(MainActivity.this).setOnReceiveListener(new OnReceiveListener() {
104 | @Override
105 | public void onConnected(Socketer socketer) {
106 |
107 | }
108 |
109 | @Override
110 | public void onDisconnected(Socketer socketer) {
111 |
112 | }
113 |
114 | @Override
115 | public void onResponse(final String data) {
116 | runOnUiThread(new Runnable() {
117 | @Override
118 | public void run() {
119 | //response data
120 | tvResponse.setTextColor(getResources().getColor(R.color.blue));
121 | tvResponse.setText(data);
122 | //... your parse ...
123 | }
124 | });
125 | }
126 | });
127 |
128 | #### Send data(发送数据)
129 | Socketer.getInstance(MainActivity.this).sendStrData(reDataStr); //request
130 |
131 |
132 |
133 |
134 |
135 | Other
136 | -----
137 |
138 | #### If you want to reconnect to other servers(如过你想重新连接另一个服务器)
139 | //If the configuration of another server is different, first configure the information
140 | //如果另一服务器配置不一样请先配置信息
141 | //Socketer.getInstance(getApplicationContext()).setEncode("UTF_8");
142 | //Socketer.getInstance(getApplicationContext()).setReceiveType(ReceiveType.SEPARATION_SIGN);
143 | //Socketer.getInstance(getApplicationContext()).setTimeout(15); ...
144 | Socketer.getInstance(getApplicationContext()).reConnectSever(ip, port);
145 |
146 |
147 |
148 | #### If you want to listen to the server connection and disconnection status(如过你想监听服务器连接与断开的状态)
149 | IntentFilter intentFilter = new IntentFilter();
150 | intentFilter.addAction(BroadCastType.NETWORK_CONNECT_STATE);
151 | ConnectReceiver dataReceiver = new ConnectReceiver();
152 | registerReceiver(dataReceiver, intentFilter);
153 |
154 |
155 | @Override
156 | public void onReceive(Context context, Intent intent) {
157 | if (intent.getAction().equals(BroadCastType.SERVER_NOTICE)) {
158 | boolean isConnected = intent.getBooleanExtra(BroadCastType.IS_CONNECTED, false);
159 | if(isConnected){
160 | Log.i(TAG, "socket connected");
161 | }else{
162 | Log.e(TAG, "socket disconnect");
163 | }
164 | }
165 | }
166 |
167 |
168 |
169 | Bugs and Feedback
170 | -----
171 |
172 | For bugs, feature requests, and discussion please use GitHub Issues
173 |
174 |
175 |
--------------------------------------------------------------------------------
/socketlibrary/src/main/java/com/virtue/socketlibrary/manager/Socketer.java:
--------------------------------------------------------------------------------
1 | package com.virtue.socketlibrary.manager;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.os.Handler;
6 | import android.os.Looper;
7 | import android.os.Message;
8 | import android.util.Log;
9 |
10 | import com.virtue.socketlibrary.type.ParseMode;
11 | import com.virtue.socketlibrary.type.ReceiveType;
12 | import com.virtue.socketlibrary.utils.OnReceiveListener;
13 | import com.virtue.socketlibrary.utils.ResponseListener;
14 | import com.virtue.socketlibrary.utils.SendBroadCastUtil;
15 | import com.virtue.socketlibrary.utils.SocketCode;
16 |
17 | import java.io.BufferedOutputStream;
18 | import java.io.DataInputStream;
19 | import java.io.IOException;
20 | import java.net.InetSocketAddress;
21 | import java.net.Socket;
22 | import java.net.SocketAddress;
23 | import java.util.ArrayList;
24 | import java.util.Collections;
25 | import java.util.Iterator;
26 | import java.util.List;
27 | import java.util.Map;
28 | import java.util.concurrent.ConcurrentHashMap;
29 | import java.util.concurrent.Executors;
30 | import java.util.concurrent.ScheduledExecutorService;
31 | import java.util.concurrent.TimeUnit;
32 |
33 | import static com.virtue.socketlibrary.type.ReceiveType.SEPARATION_SIGN;
34 |
35 | /**
36 | * Created by virtue on 2017/2/15.
37 | *
38 | * https://github.com/Zvirtuey/AndroidSocket
39 | */
40 |
41 | public class Socketer extends Thread {
42 |
43 | private static Context mContext;
44 | public Socket socket;
45 | //private BufferedWriter outputStream;
46 | private BufferedOutputStream outputStream;
47 | private DataInputStream inputStream;
48 | private static final String TAG = "Socketer";
49 | private String ip = "192.168.1.108"; //服务器地址(server address)
50 | private int port = 80; //服务器端口(server port)
51 | private int timeout = 15; //请求超时时长 单位秒(request time-out time unit sec)
52 | private int sendMaxByteLength = 1500; //发送字节数限制 单位字节(send byte limit unit byte)
53 | private boolean isRunning = true; //是否接受服务器数据(whether to accept server data)
54 | public boolean isConnected = false; //是否连接服务器(whether to connect to the server)
55 | private String encode = "UTF-8"; //编码(encode)
56 | private String endCharSequence = "\r\n"; //分割结束标识符(split end identifier)
57 | private String endData = ""; //尾部剩余数据(tail remaining data)
58 | private int msgLength = 2048; //固定长度分割(fixed-length segmentation)
59 | private ReceiveType receiveType = SEPARATION_SIGN; //接收方式(how to receive)
60 | private ParseMode parseMode = ParseMode.AUTO_PARSE; //解析方式(how to resolve)
61 | private SendMsgThread sendMsgThread;
62 | private ReceiveMsgThread receiveMsgThread;
63 | private ConcurrentHashMap mListenerMap;
64 | private ConcurrentHashMap mTimeOutMap;
65 | private List reqIdList;
66 | private OnReceiveListener mReceiveListener;
67 |
68 | private Socketer() {
69 | sendMsgThread = new SendMsgThread();
70 | receiveMsgThread = new ReceiveMsgThread();
71 | mListenerMap = new ConcurrentHashMap();
72 | mTimeOutMap = new ConcurrentHashMap();
73 | reqIdList = Collections.synchronizedList(new ArrayList());
74 | }
75 |
76 | public static final Socketer getInstance(Context context) {
77 | mContext = context.getApplicationContext();
78 | return SingleHolder.INSTANCE;
79 | }
80 |
81 | private static class SingleHolder {
82 | private static final Socketer INSTANCE = new Socketer(); // 创建实例的地方
83 | }
84 |
85 | public Socketer bindServerConnect(String address, int port) {
86 | this.ip = address;
87 | this.port = port;
88 | return this;
89 | }
90 |
91 | public void onStart() {
92 | this.start();
93 | }
94 |
95 | /**
96 | * 获取超时时间
97 | * Get timeouts
98 | *
99 | * @return
100 | */
101 | public int getTimeout() {
102 | return timeout;
103 | }
104 |
105 | /**
106 | * 设置超时时间
107 | * Set a timeout
108 | *
109 | * @param timeout
110 | * @return
111 | */
112 | public Socketer setTimeout(int timeout) {
113 | this.timeout = timeout;
114 | return this;
115 | }
116 |
117 | /**
118 | * 获取发送最大字节数
119 | * Get the maximum number of bytes to send
120 | *
121 | * @return
122 | */
123 | public int getSendMaxByteLength() {
124 | return sendMaxByteLength;
125 | }
126 |
127 | /**
128 | * 设置发送最大字节数
129 | * Set the maximum number of bytes to send
130 | *
131 | * @param sendMaxByteLength
132 | * @return
133 | */
134 | public Socketer setSendMaxByteLength(int sendMaxByteLength) {
135 | this.sendMaxByteLength = sendMaxByteLength;
136 | return this;
137 | }
138 |
139 | public String getEncode() {
140 | return encode;
141 | }
142 |
143 | /**
144 | * 设置编码
145 | * Set up the code
146 | *
147 | * @param encode
148 | * @return
149 | */
150 | public Socketer setEncode(String encode) {
151 | this.encode = encode;
152 | return this;
153 | }
154 |
155 | /**
156 | * 获取接收形式
157 | * Get the form of reception
158 | *
159 | * @return
160 | */
161 | public ReceiveType getReceiveType() {
162 | return receiveType;
163 | }
164 |
165 | /**
166 | * 设置接收形式
167 | * Set up the form of reception
168 | *
169 | * @param receiveType
170 | * @return
171 | */
172 | public Socketer setReceiveType(ReceiveType receiveType) {
173 | this.receiveType = receiveType;
174 | return this;
175 | }
176 |
177 | /**
178 | * 获取接收的固定长度值
179 | * Get a fixed-length value received
180 | *
181 | * @return
182 | */
183 | public int getMsgLength() {
184 | return msgLength;
185 | }
186 |
187 | /**
188 | * 设置接收固定长度值
189 | * Set a receive fixed length value
190 | *
191 | * @param msgLength
192 | * @return
193 | */
194 | public Socketer setMsgLength(int msgLength) {
195 | this.msgLength = msgLength;
196 | return this;
197 | }
198 |
199 | /**
200 | * 获取接收分割符
201 | * Get the receive split
202 | *
203 | * @return
204 | */
205 | public String getEndCharSequence() {
206 | return endCharSequence;
207 | }
208 |
209 | /**
210 | * 设置接收分隔符
211 | * Set the receive separator
212 | *
213 | * @param endCharSequence
214 | * @return
215 | */
216 | public Socketer setEndCharSequence(String endCharSequence) {
217 | this.endCharSequence = endCharSequence;
218 | return this;
219 | }
220 |
221 | /**
222 | * 设置响应的解析方式(默认是自动解析)
223 | * Set how the response is resolved (default is automatic resolution)
224 | *
225 | * @param mMode 解析方式枚举对象(ParseMode)
226 | * @return
227 | */
228 | public Socketer setParseMode(ParseMode mMode) {
229 | this.parseMode = mMode;
230 | return this;
231 | }
232 |
233 |
234 | /**
235 | * 获取响应时的解析方式(默认是自动解析)
236 | * How to get the resolution of the response (default is automatic resolution)
237 | *
238 | * @return
239 | */
240 | public ParseMode getParseMode() {
241 | return parseMode;
242 | }
243 |
244 | @Override
245 | public void run() {
246 | //开启超时任务
247 | scheduledExecutorService.scheduleWithFixedDelay(runnable, timeout, 1, TimeUnit.SECONDS);
248 | while (isRunning) {
249 | while (socket == null || !socket.isConnected() || isClosedServer(socket)) {
250 | try {
251 | connectSocket();
252 | Log.i(TAG, "Connecting the server");
253 | if (mReceiveListener != null) {
254 | mReceiveListener.onConnected(this);
255 | }
256 | } catch (IOException e) {
257 | e.printStackTrace();
258 | Log.e(TAG, "Connection server failed, please detect the network and server");
259 | if (isConnected == true) {
260 | isConnected = false;
261 | if (mReceiveListener != null) {
262 | mReceiveListener.onDisconnected(this);
263 | }
264 | SendBroadCastUtil.sendNetworkStateBroadcast(mContext, isConnected);
265 | }
266 | closeConnect();
267 | try {
268 | sleep(3000);
269 | } catch (InterruptedException e1) {
270 | e1.printStackTrace();
271 | }
272 | }
273 | }
274 | try {
275 | if (socket.isConnected() && inputStream != null) {
276 | if (isConnected == false) {
277 | isConnected = true;
278 | if (mReceiveListener != null) {
279 | mReceiveListener.onConnected(this);
280 | }
281 | SendBroadCastUtil.sendNetworkStateBroadcast(mContext, isConnected);
282 | }
283 | Log.i(TAG, "Connection server waiting to accept message");
284 | try {
285 | int len = 0;
286 | byte[] temp;
287 | if (msgLength > 0) {
288 | temp = new byte[msgLength];
289 | } else {
290 | temp = new byte[2048];
291 | }
292 | while ((len = inputStream.read(temp == null ? temp = new byte[2048] : temp)) != -1) {
293 |
294 | switch (receiveType) {
295 | case SEPARATION_SIGN: // 按包尾字符分割信息
296 | String tempData = new String(temp, 0, len);
297 | StringBuilder builder = new StringBuilder();
298 | builder.append(endData);
299 | builder.append(tempData);
300 | String totalStr = builder.toString();
301 | while (totalStr.contains(endCharSequence)) {
302 | String[] splitArray = totalStr.split(endCharSequence, 2);
303 | String mData = splitArray[0];
304 | endData = splitArray[1];
305 | totalStr = endData;
306 | executeReceiveTask(mData);
307 | }
308 |
309 | break;
310 |
311 | case FIXED_LENGTH: // 按固定长度分割信息
312 | if (msgLength > 0) {
313 | String allData = new String(temp, 0, len);
314 | executeReceiveTask(allData);
315 | } else {
316 | Log.e(TAG, "Set the number of bytes to receive a fixed size");
317 | }
318 |
319 | break;
320 |
321 | default:
322 | break;
323 | }
324 | }
325 | } catch (Exception e) {
326 | e.printStackTrace();
327 | Log.i(TAG, "No data to receive");
328 | }
329 | } else {
330 | inputStream = new DataInputStream(socket.getInputStream());
331 | Log.i(TAG, "Service not connected, reconnected...");
332 | }
333 | } catch (IOException e) {
334 | Log.e(TAG, "Server connection failed!");
335 | e.printStackTrace();
336 | if (socket != null) {
337 | try {
338 | socket.close();
339 | } catch (IOException e1) {
340 | e1.printStackTrace();
341 | }
342 | socket = null;
343 | }
344 | isConnected = false;
345 | if (mReceiveListener != null) {
346 | mReceiveListener.onDisconnected(this);
347 | }
348 | }
349 | }
350 | }
351 |
352 | /**
353 | * 请求服务器byte[]数据
354 | * Request server byte[] data
355 | *
356 | * @param bytes 请求byte数据
357 | * @param confirmId 服务器返回的唯一标识
358 | * @param responseListener 监听器
359 | */
360 | public synchronized void sendByteData(byte[] bytes, String confirmId, ResponseListener responseListener) {
361 | if (responseListener == null) {
362 | throw new IllegalArgumentException("responseListener must not be null");
363 | }
364 | if (isConnected) {
365 | boolean sendCode = executeSendTask(bytes, confirmId, responseListener);
366 | if (!sendCode) {
367 | responseListener.onFail(SocketCode.SEND_FAIL);
368 | }
369 | } else {
370 | responseListener.onFail(SocketCode.DISCONNECT);
371 | }
372 | }
373 |
374 | /**
375 | * 请求服务器String数据
376 | * Request server String data
377 | *
378 | * @param requestData 请求数据 (request data)
379 | * @param confirmId 服务器返回的唯一标识 (unique identity returned)
380 | * @param responseListener 监听器 (Listener)
381 | */
382 | public void sendStrData(String requestData, String confirmId, ResponseListener responseListener) {
383 | if (responseListener == null) {
384 | throw new IllegalArgumentException("responseListener must not be null");
385 | }
386 | if (isConnected) {
387 | boolean sendCode = executeSendTask(requestData, confirmId, responseListener);
388 | if (!sendCode) {
389 | responseListener.onFail(SocketCode.SEND_FAIL);
390 | }
391 | } else {
392 | responseListener.onFail(SocketCode.DISCONNECT);
393 | }
394 | }
395 |
396 | /**
397 | * 请求服务器String数据
398 | * Request server String data
399 | *
400 | * @param requestData 请求数据 (request data)
401 | * @return
402 | */
403 | public boolean sendStrData(String requestData) {
404 | boolean sendResult = false;
405 | if (isConnected) {
406 | sendResult = executeSendTask(requestData, null, null);
407 | }
408 | return sendResult;
409 | }
410 |
411 | private void connectSocket() throws IOException {
412 | endData = "";
413 | socket = new Socket();
414 | SocketAddress socketAddress = new InetSocketAddress(ip, port);
415 | socket.connect(socketAddress, 5 * 1000);
416 | socket.setTcpNoDelay(true); // 关闭 Nagle 算法
417 | socket.setReceiveBufferSize(1024 * 10000);
418 | outputStream = new BufferedOutputStream(socket.getOutputStream());
419 | //outputStream = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), encode));
420 | inputStream = new DataInputStream(socket.getInputStream());
421 | isRunning = true;
422 | }
423 |
424 | /**
425 | * 重新连接服务器,可以换服务器地址、端口
426 | * 如果重新连接的服务器配置信息不一样请先设置各个配置(如编码、解析方式、超时时间等),然后再调用此方法
427 | * Reconnect the server, you can change the server address and port, If the reconnected server
428 | * configuration information is different, set up individual configurations (e.g. encoding, resolution, timeout, etc.)
429 | * before calling this method.
430 | *
431 | * @param ip
432 | * @param port
433 | */
434 | public void reConnectSever(String ip, int port) {
435 | boolean isAlive = isAlive();
436 | if (isAlive) {
437 | Socketer.getInstance(mContext).closeConnect();
438 | Socketer.getInstance(mContext).closeSocketer();
439 | } else {
440 | bindServerConnect(ip, port).start();
441 | }
442 | Socketer.getInstance(mContext).bindServerConnect(ip, port);
443 |
444 | }
445 |
446 | /**
447 | * 关闭连接
448 | * close socket
449 | */
450 | public void closeConnect() {
451 | try {
452 | if (socket != null) {
453 | if (inputStream != null) {
454 | inputStream.close();
455 | }
456 | if (outputStream != null) {
457 | outputStream.close();
458 | }
459 | }
460 | } catch (Exception e) {
461 | e.printStackTrace(); // 关闭连接失败 close fail
462 | } finally {
463 | try {
464 | if (socket != null) {
465 | socket.close();
466 | socket = null;
467 | }
468 | } catch (IOException e) {
469 | e.printStackTrace();
470 | }
471 | }
472 | }
473 |
474 | public void closeSocketer() {
475 | reqIdList.clear();
476 | mTimeOutMap.clear();
477 | mListenerMap.clear();
478 | ip = "";
479 | }
480 |
481 | public Boolean isClosedServer(Socket socket) {
482 | try {
483 | socket.sendUrgentData(0xFF);// 发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信
484 | return false;
485 | } catch (Exception e) {
486 | return true;
487 | }
488 | }
489 |
490 | public synchronized boolean executeSendTask(byte[] data, String requestId, ResponseListener mListener) {
491 | if (sendMsgThread == null || !sendMsgThread.isAlive()) {
492 | sendMsgThread = new SendMsgThread();
493 | synchronized (sendMsgThread) {
494 | sendMsgThread.start();
495 | try {
496 | sendMsgThread.wait();
497 | } catch (Exception e) {
498 | e.printStackTrace();
499 | }
500 | }
501 | }
502 | if (sendMsgThread.mLooper == null || sendMsgThread.mHandler == null) {
503 | Log.e(TAG, "workerThread mLooper mHandler ERROR!");
504 | return false;
505 | }
506 | Message msg = Message.obtain();
507 | Bundle bundle = new Bundle();
508 | bundle.putByteArray("byte", data);
509 | bundle.putString("msgId", requestId);
510 | msg.setData(bundle);
511 | msg.obj = mListener;
512 | return sendMsgThread.mHandler.sendMessage(msg);
513 | }
514 |
515 | public synchronized boolean executeSendTask(String data, String requestId, ResponseListener mListener) {
516 | if (sendMsgThread == null || !sendMsgThread.isAlive()) {
517 | sendMsgThread = new SendMsgThread();
518 | synchronized (sendMsgThread) {
519 | sendMsgThread.start();
520 | try {
521 | sendMsgThread.wait();
522 | } catch (Exception e) {
523 | e.printStackTrace();
524 | }
525 | }
526 | }
527 | if (sendMsgThread.mLooper == null || sendMsgThread.mHandler == null) {
528 | Log.e(TAG, "workerThread mLooper mHandler ERROR!");
529 | return false;
530 | }
531 | Message msg = Message.obtain();
532 | Bundle bundle = new Bundle();
533 | bundle.putString("content", data);
534 | bundle.putString("msgId", requestId);
535 | msg.setData(bundle);
536 | msg.obj = mListener;
537 | return sendMsgThread.mHandler.sendMessage(msg);
538 | }
539 |
540 | public synchronized boolean executeReceiveTask(String data) {
541 | if (receiveMsgThread == null || !receiveMsgThread.isAlive()) {
542 | receiveMsgThread = new ReceiveMsgThread();
543 | synchronized (receiveMsgThread) {
544 | receiveMsgThread.start();
545 | try {
546 | receiveMsgThread.wait();
547 | } catch (Exception e) {
548 | e.printStackTrace();
549 | }
550 | }
551 | }
552 | if (receiveMsgThread.mReceiveLooper == null || receiveMsgThread.mHandler == null) {
553 | Log.e(TAG, "receiveMsgThread mLooper mHandler ERROR!");
554 | return false;
555 | }
556 | Message msg = Message.obtain();
557 | msg.obj = data;
558 | return receiveMsgThread.mHandler.sendMessage(msg);
559 | }
560 |
561 | public class SendMsgThread extends Thread {
562 | protected final String TAG = "SendMsgThread";
563 | private Handler mHandler;
564 | private Looper mLooper;
565 |
566 | public void run() {
567 | Looper.prepare();
568 | mLooper = Looper.myLooper();
569 | mHandler = new Handler(mLooper) {
570 | public void handleMessage(Message msg) {
571 | Bundle mArgs = msg.getData();
572 | byte[] mBytes = mArgs.getByteArray("byte");
573 | String mData = mArgs.getString("content");
574 | String mReqId = mArgs.getString("msgId");
575 | ResponseListener responseListener = (ResponseListener) msg.obj;
576 | if (mData != null && !mData.equals("") && mData.length() > 0) {
577 | mBytes = mData.getBytes();
578 | }
579 | if (socket == null || !socket.isConnected()) {
580 | try {
581 | connectSocket();
582 | } catch (IOException e) {
583 | e.printStackTrace();
584 | if (parseMode == ParseMode.AUTO_PARSE) {
585 | responseListener.onFail(SocketCode.DISCONNECT);
586 | }
587 | Log.e(TAG, "Failed to connect to the server, please detect the network -->" + e);
588 | return;
589 | }
590 | }
591 | if (outputStream == null) {
592 | try {
593 | outputStream = new BufferedOutputStream(socket.getOutputStream());
594 | //outputStream = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), encode));
595 | } catch (IOException e) {
596 | e.printStackTrace();
597 | if (parseMode == ParseMode.AUTO_PARSE) {
598 | responseListener.onFail(SocketCode.SEND_FAIL);
599 | }
600 | Log.e(TAG, "Failed to send a fetch stream -->" + e);
601 | return;
602 | }
603 | }
604 | Log.i(TAG, "The length of the requested data :" + mData.length() + "\nRequest data :" + mData);
605 | if (mBytes.length > sendMaxByteLength
606 | && parseMode == ParseMode.AUTO_PARSE) {
607 | responseListener.onFail(SocketCode.SEND_TO_LONG);
608 | return;
609 | }
610 |
611 | try {
612 | if (mReqId != null && !mReqId.equals("")
613 | && parseMode == ParseMode.AUTO_PARSE) {
614 | mListenerMap.put(mReqId, responseListener);
615 | reqIdList.add(mReqId);
616 | long sendTime = System.currentTimeMillis();
617 | mTimeOutMap.put(mReqId, sendTime);
618 | }
619 | outputStream.write(mBytes);
620 | outputStream.flush();
621 | Log.i(TAG, "message send successful");
622 | } catch (IOException e) {
623 | e.printStackTrace();
624 | if (parseMode == ParseMode.AUTO_PARSE) {
625 | responseListener.onFail(SocketCode.SEND_FAIL);
626 | }
627 | Log.e(TAG, "send failed -->" + e);
628 | try {
629 | socket.close();
630 | } catch (IOException e1) {
631 | e1.printStackTrace();
632 | Log.e(TAG, "close stream failed -->" + e1);
633 | }
634 | socket = null;
635 | return;
636 | }
637 | }
638 | };
639 | synchronized (this) {
640 | try {
641 | notify();
642 | } catch (Exception e) {
643 | e.printStackTrace();
644 | }
645 | }
646 | Looper.loop();
647 | }
648 | }
649 |
650 | public class ReceiveMsgThread extends Thread {
651 | protected final String TAG = "ReceiveMsgThread";
652 | private Handler mHandler;
653 | private Looper mReceiveLooper;
654 |
655 | public void run() {
656 | Looper.prepare();
657 | mReceiveLooper = Looper.myLooper();
658 | mHandler = new Handler(mReceiveLooper) {
659 | public void handleMessage(Message msg) {
660 | String mData = (String) msg.obj;
661 | Log.v(TAG, "reqIdList size: " + reqIdList.size() + "\nData returned by the server:" + "\n" + mData);
662 | switch (parseMode) {
663 | case AUTO_PARSE: //自动解析 Auto Parse
664 | autoParseData(mData);
665 |
666 | break;
667 | case MANUALLY_PARSE: //手动解析 Manually Parse
668 | if (mReceiveListener != null) {
669 | mReceiveListener.onResponse(mData);
670 | }
671 |
672 | break;
673 |
674 | default:
675 |
676 | break;
677 | }
678 | }
679 | };
680 | synchronized (this) {
681 | try {
682 | notify();
683 | } catch (Exception e) {
684 | e.printStackTrace();
685 | }
686 | }
687 | Looper.loop();
688 | }
689 |
690 | private void autoParseData(String mData) {
691 | if (reqIdList == null || reqIdList.size() <= 0) {
692 | SendBroadCastUtil.sendServerData(mContext, mData);
693 | return;
694 | }
695 | for (String mStr : reqIdList) {
696 | Log.v(TAG, mStr);
697 | if (mData.contains(mStr)) {
698 | if (mListenerMap.containsKey(mStr)) {
699 | ResponseListener responseListener = mListenerMap.get(mStr);
700 | responseListener.onSuccess(mData);
701 | mListenerMap.remove(mStr);
702 | reqIdList.remove(mStr);
703 | if (mTimeOutMap.containsKey(mStr)) {
704 | mTimeOutMap.remove(mStr);
705 | }
706 | }
707 | } else {
708 | SendBroadCastUtil.sendServerData(mContext, mData);
709 | }
710 | }
711 | }
712 | }
713 |
714 | public void setOnReceiveListener(OnReceiveListener receiveListener) {
715 | if (receiveListener == null) {
716 | throw new IllegalArgumentException("receiveListener must not be null");
717 | }
718 | mReceiveListener = receiveListener;
719 |
720 | }
721 |
722 | private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
723 | //超时处理(Time out)
724 | private Runnable runnable = new Runnable() {
725 | @Override
726 | public void run() {
727 | if (mTimeOutMap != null && mTimeOutMap.size() > 0) {
728 | long receiveTime = System.currentTimeMillis();
729 | Iterator> entries = mTimeOutMap.entrySet().iterator();
730 | while (entries.hasNext()) {
731 | Map.Entry entry = entries.next();
732 | String reStrId = entry.getKey();
733 | long sendTime = entry.getValue();
734 | if (receiveTime - sendTime > timeout * 1000) {
735 | if (mListenerMap.containsKey(reStrId)) {
736 | ResponseListener responseListener = mListenerMap.get(reStrId);
737 | responseListener.onFail(SocketCode.TIME_OUT);
738 | mListenerMap.remove(reStrId);
739 | mTimeOutMap.remove(reStrId);
740 | if (reqIdList.contains(reStrId)) {
741 | reqIdList.remove(reStrId);
742 | }
743 | }
744 | }
745 | System.out.println("Time out Key = " + entry.getKey() + ", Time outValue = " + entry.getValue());
746 | }
747 | }
748 | }
749 | };
750 |
751 |
752 | }
753 |
--------------------------------------------------------------------------------