Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.ecv.socketexample.socket;
- import android.app.Service;
- import android.content.Intent;
- import android.os.Binder;
- import android.os.Handler;
- import android.os.HandlerThread;
- import android.os.IBinder;
- import android.util.Log;
- import org.json.JSONException;
- import org.json.JSONObject;
- import java.io.BufferedReader;
- import java.io.InputStreamReader;
- import java.io.PrintWriter;
- import java.net.InetSocketAddress;
- import java.net.Socket;
- import java.net.SocketAddress;
- import java.util.Iterator;
- import java.util.concurrent.ConcurrentLinkedQueue;
- /**
- * Created by pedro on 16/07/17.
- */
- public class ConnectionService extends Service {
- /**
- * Binder
- */
- public class ConnectionBinder extends Binder {
- /**
- * Get Service
- * @return
- */
- public ConnectionService getService() {
- return ConnectionService.this;
- }
- }
- /**
- * Request Result
- *
- */
- public interface RequestResult {
- /** On result */
- public void onResult(int result, String message);
- }
- /**
- * Socket Listener
- */
- public interface SocketListener {
- /**
- * On Disconnected
- */
- public void onDisconnected();
- /**
- * On Received Data
- *
- * @param data
- */
- public void onReceivedData(String data);
- }
- /**
- * Message
- */
- public class Message {
- //
- int control;
- String message;
- long dispatchTime;
- /**
- * Constructor
- *
- * @param message
- * @param dispatchTime
- */
- public Message(final int control, final String message, final long dispatchTime) {
- this.control = control;
- this.message = message;
- this.dispatchTime = dispatchTime;
- }
- }
- //
- ConnectionBinder mBinder = new ConnectionBinder();
- Socket mClientSocket = null;
- volatile int mLoginControl = 0; /* To invalidate invalid connections */
- Handler mHandler;
- volatile SocketListener mSocketListener;
- volatile boolean mConnected = false;
- //
- private BufferedReader in = null;
- private PrintWriter out = null;
- private volatile long mPingAlarmClock = 0;
- //
- final private ConcurrentLinkedQueue<Message> mMessages = new ConcurrentLinkedQueue<>();
- /**
- * On bind
- * @param intent
- * @return
- */
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
- /**
- * On created
- */
- @Override
- public void onCreate() {
- super.onCreate();
- Log.d("LogTest", "Created service");
- //
- HandlerThread thread = new HandlerThread("ConnectionHT", android.os.Process.THREAD_PRIORITY_BACKGROUND);
- thread.start();
- mHandler = new Handler(thread.getLooper());
- }
- /**
- * Call runnable
- *
- * @param control
- * @param runnable
- */
- public void callRunnable(final int control, final Runnable runnable) {
- /**
- * Post result to ui thread
- */
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if(mLoginControl == control)
- runnable.run();
- }
- });
- }
- /**
- * Dispatch Message
- *
- * @param message
- * @param delayed
- */
- private void dispatchMessage(final String message, final int delayed, final int control) {
- // Prevent invalid messages
- if(control == mLoginControl)
- mMessages.add(new Message(control, message, System.currentTimeMillis() + delayed));
- }
- /**
- * Dispatch Message
- *
- * @param message
- */
- private void dispatchMessage(final String message, final int control) {
- // Prevent invalid messages
- if(control == mLoginControl)
- mMessages.add(new Message(control, message, System.currentTimeMillis()));
- }
- /**
- * Dispatch Message
- *
- * @param message
- * @param delayed
- */
- public void sendMessage(final String message, final int delayed) {
- if(isConnected())
- mMessages.add(new Message(mLoginControl, message, System.currentTimeMillis() + delayed));
- }
- /**
- * Dispatch Message
- *
- * @param message
- */
- public void sendMessage(final String message) {
- if(isConnected())
- mMessages.add(new Message(mLoginControl, message, System.currentTimeMillis()));
- }
- /**
- * Ping Socket
- */
- private void pingSocket(final int control, final int delay) {
- // Heartbeat JSON
- final JSONObject heartbeatJson = new JSONObject();
- try {
- heartbeatJson.put("action", "ping");
- } catch (Exception e) {
- Log.d("LogTest", "Error on make json.");
- }
- //
- Log.d("LogTest", "Dispatched ping in control " + control + " of " + mLoginControl);
- dispatchMessage(heartbeatJson.toString(), delay, control);
- // Set Alarm
- mPingAlarmClock = System.currentTimeMillis() + ConnectUtils.HEARTBEAT_ALARM_CLOCK;
- Log.d("LogTest", "Set alarm (" + mPingAlarmClock + ") in control " + control + " of " + mLoginControl);
- //
- final long setPing = mPingAlarmClock;
- // Set Alarm Checker
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- if(mLoginControl == control && mPingAlarmClock <= setPing) {
- Log.d("LogTest", "Dont received pong (" + mPingAlarmClock + ", " + System.currentTimeMillis() + ") in control " + control + " of " + mLoginControl);
- if(mSocketListener != null)
- mSocketListener.onDisconnected();
- }
- }
- }, ConnectUtils.HEARTBEAT_ALARM_CLOCK + 100);
- }
- /**
- * Start Receiver Thread
- */
- public void startSocketControlThread(final BufferedReader in, final PrintWriter out, final int control) {
- //
- new Thread(new Runnable() {
- /**
- * Run
- */
- @Override
- public void run() {
- // First Heartbeat
- Log.d("LogTest", "Socket control(" + control + ") created");
- Log.d("LogTest", "First ping");
- pingSocket(control, 0);
- //
- while(true) {
- //
- //
- if(mLoginControl != control) {
- Log.d("LogTest", "SocketControl(receive)(" + mLoginControl + ") is dead");
- break;
- }
- //
- try {
- // This if is to read if have mReceiver
- if(mSocketListener != null) {
- String data = ConnectUtils.readText(in, 10000);
- Log.d("LogTest", "Received data: " + data);
- // This if is to prevent read delay
- if(mSocketListener != null && mLoginControl == control) {
- boolean consumed = false;
- try {
- JSONObject receivedJson = new JSONObject(data);
- if(!receivedJson.isNull("messageType")) {
- final String type = receivedJson.getString("messageType");
- if (type.equals("pong")) {
- Log.d("LogTest", "Received pong.");
- pingSocket(control, ConnectUtils.HEARTBEAT_TIME);
- consumed = true;
- }
- }
- } catch (Exception e) {}
- if(!consumed) {
- mSocketListener.onReceivedData(data);
- } else {
- Log.d("LogTest", "Consumed message " + data + " from server.");
- }
- }
- }
- } catch (Exception e) {
- Log.d("LogTest", "Error in control " + control + " of " + mLoginControl + ". " + e.getMessage());
- }
- //
- try {
- Thread.sleep(10);
- } catch (Exception e) {
- Log.d("LogTest", "Socket control dead in control " + control + " of " + mLoginControl + ". Error: " + e.getMessage());
- // If error on sleep break this while(true){..}
- break;
- }
- }
- }
- }).start();
- //
- //
- new Thread(new Runnable() {
- /**
- * Run
- */
- @Override
- public void run() {
- // First Heartbeat
- Log.d("LogTest", "Socket control(" + control + ") created");
- Log.d("LogTest", "First ping");
- pingSocket(control, 0);
- //
- while(true) {
- //
- //
- if(mLoginControl != control) {
- Log.d("LogTest", "SocketControl(Receive)(" + mLoginControl + ") is dead");
- break;
- }
- //
- try {
- // Dispatch messages
- while(mMessages.size() > 0) {
- Iterator<Message> itr = mMessages.iterator();
- while(itr.hasNext()) {
- final Message m = itr.next();
- if(mLoginControl == m.control && System.currentTimeMillis() > m.dispatchTime) {
- out.println(m.message);
- out.flush();
- itr.remove();
- //
- Log.d("LogTest", "Dispatched message to server " + m.message);
- }
- }
- }
- } catch (Exception e) {
- Log.d("LogTest", "Error in control " + control + " of " + mLoginControl + ". " + e.getMessage());
- }
- //
- try {
- Thread.sleep(10);
- } catch (Exception e) {
- Log.d("LogTest", "Socket control dead in control " + control + " of " + mLoginControl + ". Error: " + e.getMessage());
- // If error on sleep break this while(true){..}
- break;
- }
- }
- }
- }).start();
- }
- /**
- * It starts the login process, if this function is called twice or more times overlapping
- * login processes that were in progress, it is prepared to ignore the previous results using
- * the login control.
- *
- * @param accountNumber
- * @param imei
- * @param password
- */
- public void startLogin(final String accountNumber, final String imei, final String password, final RequestResult runnable) {
- /** Invalidate others logins (if have) */
- logout();
- final int control = mLoginControl;
- /** Start new login thread */
- new Thread(new Runnable() {
- /**
- * Run
- */
- @Override
- public void run() {
- try {
- Log.d("LogTest", "Created address");
- SocketAddress socketAddress = new InetSocketAddress(ConnectUtils.HOST, ConnectUtils.POST);
- final Socket socket = new Socket();
- Log.d("LogTest", "Start connecting");
- socket.connect(socketAddress, 10000);
- Log.d("LogTest", "End connecting");
- //
- if(socket.isConnected()) {
- Log.d("LogTest", "A");
- in = new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));
- out = new PrintWriter(socket.getOutputStream());
- Log.d("LogTest", "B");
- //
- JSONObject json = new JSONObject();
- json.put("action", "login");
- json.put("language", "zh_CN");
- json.put("accountNumber", accountNumber);
- json.put("imei", imei);
- json.put("password", password);
- Log.d("LogTest", "C: " + json.toString());
- // Start login
- out.println(json.toString());
- out.flush();
- Log.d("LogTest", "D");
- // Wait 20s
- final String received = ConnectUtils.readText(in, 100000);
- Log.d("LogTest", "E");
- //
- try {
- //
- Log.d("LogTest", "Received: " + received);
- final JSONObject receivedJson = new JSONObject(received);
- Log.d("LogTest", "F");
- String flag = receivedJson.getString("flag");
- if(flag.trim().equals("00")) {
- //
- callRunnable(control, new Runnable() {
- @Override
- public void run() {
- mConnected = true;
- mClientSocket = socket;
- // Start receiver thread
- startSocketControlThread(in, out, control);
- // Ok
- runnable.onResult(1, "Just here, okay: " + receivedJson);
- }
- });
- } else {
- //
- callRunnable(control, new Runnable() {
- @Override
- public void run() {
- mConnected = false;
- mClientSocket = null;
- runnable.onResult(-1, "Wrong loging account: " + receivedJson);
- }
- });
- }
- } catch (JSONException jsonE) {
- Log.d("LogTest", "Error: " + jsonE);
- callRunnable(control, new Runnable() {
- @Override
- public void run() {
- runnable.onResult(-1, "Could not recognize data received after login: " + received);
- }
- });
- }
- Log.d("LogTest", "G");
- } else {
- callRunnable(control, new Runnable() {
- @Override
- public void run() {
- runnable.onResult(-1, "Could not connect to socket.");
- }
- });
- }
- //
- } catch (final Exception e) {
- callRunnable(control, new Runnable() {
- @Override
- public void run() {
- runnable.onResult(-1, "Error on connect (" + accountNumber + ", " + imei + ", " + password + ") with control " + control + " and global control " + mLoginControl + ". Error: " + e.getMessage());
- }
- });
- }
- }
- }).start();
- }
- /**
- * It starts the reconnection process, if this function is called twice or more times overlapping
- * login processes that were in progress, it is prepared to ignore the previous results using
- * the login control.
- *
- * @param accountNumber
- * @param imei
- * @param password
- */
- public void startReconnection(final String accountNumber, final String imei, final String password, final RequestResult runnable) {
- /** Invalidate others logins (if have) */
- logout();
- final int control = mLoginControl;
- /** Start new login thread */
- new Thread(new Runnable() {
- /**
- * Run
- */
- @Override
- public void run() {
- try {
- Log.d("LogTest", "Created address");
- SocketAddress socketAddress = new InetSocketAddress(ConnectUtils.HOST, ConnectUtils.POST);
- final Socket socket = new Socket();
- Log.d("LogTest", "Start connecting");
- socket.connect(socketAddress, 10000);
- Log.d("LogTest", "End connecting");
- //
- if(socket.isConnected()) {
- Log.d("LogTest", "A");
- in = new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));
- out = new PrintWriter(socket.getOutputStream());
- Log.d("LogTest", "B");
- //
- JSONObject json = new JSONObject();
- json.put("action", "reconnect");
- json.put("language", "zh_CN");
- json.put("accountNumber", accountNumber);
- json.put("imei", imei);
- json.put("password", password);
- Log.d("LogTest", "C: " + json.toString());
- // Start login
- out.println(json.toString());
- out.flush();
- Log.d("LogTest", "D");
- // Wait 20s
- final String received = ConnectUtils.readText(in, 100000);
- Log.d("LogTest", "E");
- //
- try {
- //
- Log.d("LogTest", "Received: " + received);
- final JSONObject receivedJson = new JSONObject(received);
- Log.d("LogTest", "F");
- String flag = receivedJson.getString("flag");
- Log.d("LogTest", "Get flag: " + flag);
- if(flag.trim().equals("00")) {
- Log.d("LogTest", "Reconnected");
- //
- callRunnable(control, new Runnable() {
- @Override
- public void run() {
- mConnected = true;
- mClientSocket = socket;
- Log.d("LogTest", "Saved Socket and start socket controller");
- // Start receiver thread
- startSocketControlThread(in, out, control);
- Log.d("LogTest", "Just here okay");
- // Ok
- runnable.onResult(1, "Just here, okay: " + receivedJson);
- }
- });
- } else {
- Log.d("LogTest", "Error on reconnect");
- //
- callRunnable(control, new Runnable() {
- @Override
- public void run() {
- mConnected = false;
- mClientSocket = null;
- runnable.onResult(-2, "Wrong loging account: " + receivedJson);
- }
- });
- }
- } catch (JSONException jsonE) {
- Log.d("LogTest", "Error: " + jsonE);
- callRunnable(control, new Runnable() {
- @Override
- public void run() {
- runnable.onResult(-1, "Could not recognize data received after login: " + received);
- }
- });
- }
- Log.d("LogTest", "G");
- } else {
- Log.d("LogTest", "Socket dont connected");
- callRunnable(control, new Runnable() {
- @Override
- public void run() {
- runnable.onResult(-1, "Could not connect to socket.");
- }
- });
- }
- //
- } catch (final Exception e) {
- Log.d("LogTest", "Error on connect (: " + e.getMessage());
- callRunnable(control, new Runnable() {
- @Override
- public void run() {
- runnable.onResult(-1, "Error on connect (" + accountNumber + ", " + imei + ", " + password + ") with control " + control + " and global control " + mLoginControl + ". Error: " + e.getMessage());
- }
- });
- }
- }
- }).start();
- }
- /**
- * Logout
- */
- public void logout() {
- mLoginControl++;
- mClientSocket = null;
- mConnected = false;
- mMessages.clear();
- mPingAlarmClock = 0;
- in = null;
- out = null;
- }
- /**
- * Is connected
- *
- * @return
- */
- public boolean isConnected() {
- return mConnected && mClientSocket != null;
- }
- /**
- * Set Receiver
- *
- * @param listener
- */
- public void setSocketListener(final SocketListener listener) {
- mSocketListener = listener;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement