Android SocketService

package com.freer.infusion.module.service;

import android.app.ActivityManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Parcelable;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import com.freer.infusion.R;
import com.freer.infusion.config.AppConfig;
import com.freer.infusion.entity.SocketEntity;
import com.freer.infusion.model.SocketDataModel;
import com.freer.infusion.model.SocketDataProcess;
import com.freer.infusion.module.main.MainActivity;
import com.freer.infusion.util.JsonUtils;
import com.freer.infusion.util.NetUtils;
import com.freer.infusion.util.ScreenLockLocation;
import com.freer.infusion.util.ThreadManager;
import com.freer.infusion.util.ToastUtils;
import com.google.gson.FieldAttributes;

import org.apache.http.conn.ConnectTimeoutException;

import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.net.ConnectException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;

/**
 * Created by 2172980000774 on 2016/5/12.
 */
public class SocketService extends Service {

    /* handler消息標誌 */
    private static final int HANDLER_DEBUG = 0; //Debug數據
    private static final int HANDLER_SERVER = 1; //服務器數據
    private static final int HANDLER_LOCAL = 2; //本地數據
    private static final int HANDLER_ERROR = 3; //掃描服務器失敗

    private static final String CHECK_CONN = "{\"cate\":8,\"d\":[]}"; //鏈接確認
    private static final String HEART_BEAT = "{\"cate\":9,\"d\":[]}"; //心跳檢測

    private static final long HEART_BEAT_RATE = 15 * 1000; //心跳檢測間隔時間
    private static final long CONN_CHECK_RATE = 5 * 1000; //掃描服務器超時時間

    public static String HOST = null; //服務器IP地址
    public static int PORT = 2020; //服務器端口號

    public static final String MESSAGE_ACTION="message_action";
    public static final String HEART_BEAT_ACTION="heart_beat_action";
    public static final String CONN_CHECK_ACTION = "conn_check_action";
    public static final String CONN_ERROR_ACTION = "conn_error_action";
    public static final String NO_CONN_ACTION = "no_conn_action";

    private ReadThread mReadThread;

    private LocalBroadcastManager mLocalBroadcastManager;

    private WeakReference<Socket> mSocket;

    private SocketDataProcess mSocketDataProcess = new SocketDataProcess();
    private SocketDataModel mFollowModel = new SocketDataModel();
    private SocketDataModel mAllModel = new SocketDataModel();

    private ScreenLockLocation mScreenLockLocation;

    /** For Heart Beat */
    private long sendTime = 0L;
    private Handler mHeartBeatHandler = new Handler();
    private Runnable heartBeatRunnable = new Runnable() {

        @Override
        public void run() {
            if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) {
                if (!sendMsg(null)) { //就發送一個心跳數據過去 若是發送失敗,就從新初始化一個socket
                    // 發送失敗處理
                    release();
                    // 首先判斷本地是否服務器記錄,若是沒有則已經作過遍歷並鏈接失敗,直接通知用戶服務器鏈接失敗
                    if (HOST == null) {
                        Message sendFail = mMsgHandler.obtainMessage();
                        sendFail.what = HANDLER_ERROR;
                        sendFail.sendToTarget();
                    } else {
                        ThreadManager.getInstance().addTask(new CheckConnRunnable(HOST));
//                        new Thread(new CheckConnRunnable(HOST)).start();
                    }
                }
            }
            mHeartBeatHandler.postDelayed(this, HEART_BEAT_RATE);
        }
    };

    /**
     * 更新主界面數據接口
     */
    public interface IReceiveMessage {
        void receiveMessage(List<SocketEntity> followBedList, List<SocketEntity> allBedList);
    }
    private IReceiveMessage mIReceiveMessage;

    public class SocketBinder extends Binder {
        public boolean sendMessage(SocketEntity message) {
            return sendMsg(message);
        }

        public void setOnReveiveMessage(IReceiveMessage iReceiveMessage) {
            mIReceiveMessage = iReceiveMessage;
        }

        public void reStart() {
            // 釋放以前的資源
            release();
            // 從新初始化socket
            String ip = AppConfig.getInstance().getServerIp();
            if (ip != null && !ip.equals("")) {
                ThreadManager.getInstance().addTask(new CheckConnRunnable(ip));
//                new Thread(new CheckConnRunnable(ip)).start();
            } else {
                if (HOST != null) {
                    ThreadManager.getInstance().addTask(new CheckConnRunnable(HOST));
//                    new Thread(new CheckConnRunnable(HOST)).start();
                } else {
                    scanIpSegment();
                }
            }
        }
    }

    /**
     * 開始鏈接服務器
     */
    public void startWork() {
        String ip = AppConfig.getInstance().getServerIp();
        if (ip != null && !ip.equals("")) {
//            new Thread(new CheckConnRunnable(ip)).start();
            ThreadManager.getInstance().addTask(new CheckConnRunnable(ip));
        } else {
            scanIpSegment();
        }
    }

    public SocketBinder mSocketBinder;

    @Override
    public IBinder onBind(Intent arg0) {
        return mSocketBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mScreenLockLocation = new ScreenLockLocation(this);
        mScreenLockLocation.start();

        Intent intent =  new Intent(this, MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

        startForeground(1,
                new NotificationCompat.Builder(this)
                        .setSmallIcon(R.drawable.ic_launcher)
                        .setContentTitle(SocketService.this.getString(R.string.navi_title))
                        .setContentText(SocketService.this.getString(R.string.navi_content))
                        .setShowWhen(false)
                        .setOngoing(true)
                        .setContentIntent(PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT))
                        .build());

        mSocketBinder = new SocketBinder();
        mLocalBroadcastManager=LocalBroadcastManager.getInstance(this);

//        new InitSocketThread().start();
        startWork();
//        ThreadManager.getInstance().addTask(new CheckConnRunnable("192.168.1.3"));
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e("SocketService", "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.e("SocketService", "onDestroy");
        mScreenLockLocation.stop();
        stopForeground(true);
        stopWork();
        super.onDestroy();
    }

    public boolean sendMsg(SocketEntity msg) {
        if (null == mSocket || null == mSocket.get()) {
            return false;
        }
        Socket soc = mSocket.get();
        try {
            if (!soc.isClosed() && !soc.isOutputShutdown()) {
                OutputStream os = soc.getOutputStream();
                // 若是爲null,說明是心跳檢測,不然就是本地主動設置的數據
                String message =
                        msg == null ?
                                HEART_BEAT : "{\"cate\":0,\"d\":["+msg.toString()+"]}";
                os.write(message.getBytes());
                os.flush();
                //發送成功處理
                sendTime = System.currentTimeMillis(); //每次發送成數據,就改一下最後成功發送的時間,節省心跳間隔時間
                if (msg != null) { //確認是本地主動修改發送給服務器的數據
                    Message sendSuccess = mMsgHandler.obtainMessage();
                    sendSuccess.what = HANDLER_LOCAL;
                    sendSuccess.obj = msg.toString();
                    sendSuccess.sendToTarget();
                }
                return true;
            }
        } catch (IOException e) {
            System.out.println("發送失敗");
        }
        return false;
    }

    private void initSocket() { // 初始化Socket
        try {
            Socket so = new Socket(HOST, PORT);
            mSocket = new WeakReference<>(so);
            mReadThread = new ReadThread(so);
            mReadThread.start();
            mHeartBeatHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);//初始化成功後,就準備發送心跳包
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 在遍歷ip以後,第一次鏈接調用
     * @param socket
     */
    private void initSocket(Socket socket) {
        mSocket = new WeakReference<Socket>(socket);
        mReadThread = new ReadThread(socket);
        mReadThread.start();
        mHeartBeatHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE); // 初始化成功後,就準備發送心跳包
    }

    private void releaseLastSocket(WeakReference<Socket> mSocket) {
        try {
            if (null != mSocket) {
                Socket sk = mSocket.get();
                if (sk != null && !sk.isClosed()) {
                    sk.close();
                }
                sk = null;
                mSocket = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    class InitSocketThread extends Thread {
        @Override
        public void run() {
            super.run();
            initSocket();
        }
    }

    // Thread to read content from Socket
    class ReadThread extends Thread {
        private WeakReference<Socket> weakSocket;
        private boolean isStart = true;

        public ReadThread(Socket socket) {
            weakSocket = new WeakReference<Socket>(socket);
        }

        public void release() {
            isStart = false;
            releaseLastSocket(weakSocket);
        }

        @Override
        public void run() {
            super.run();
            Socket socket = weakSocket.get();
            receiveMsg(socket, isStart);
        }
    }

    public void receiveMsg(Socket socket, boolean isStart) {
        if (null != socket) {
            try {
                InputStream is = socket.getInputStream();
                byte[] buffer = new byte[1024 * 4];
                int length = 0;
                while (!socket.isClosed() && !socket.isInputShutdown()
                        && isStart && ((length = is.read(buffer)) != -1)) {
                    if (length > 0) {
                        String message = new String(Arrays.copyOf(buffer,
                                length)).trim();
                        System.out.println("收到Socket服務器回覆");
                        //收到服務器過來的消息,就經過Broadcast發送出去
                        if(message.contains("\"cate\":9")){//處理心跳回復
                            System.out.println("當前回覆爲心跳檢測");
//                            Intent intent=new Intent(HEART_BEAT_ACTION);
//                            mLocalBroadcastManager.sendBroadcast(intent);
                        }else if (message.contains("\"cate\":0")){
                            System.out.println("當前回覆爲其餘回覆");
                            //其餘消息回覆
                            Message msg = mMsgHandler.obtainMessage();
                            msg.what = HANDLER_SERVER;
                            msg.obj = message;
                            msg.sendToTarget();
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 經過回調的方式通知activity
     * 經過handler從子線程傳遞數據到主線程中
     */
    private Handler mMsgHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == HANDLER_SERVER) { //收到服務器傳遞的數據
                sendTime = System.currentTimeMillis(); //每一次成功接收到服務器主動發送的消息,更新時間
                if (msg!=null && msg.obj != null) {
                    System.out.println("收到原始數據"+msg.obj.toString());
                }
                String data = (String) msg.obj;
//                mSocketDataProcess.processData(data);
                mFollowModel.processData(data, true);
                mAllModel.processData(data, false);
                //考慮一下,由於ReceiveMessage須要在成功綁定以後才能獲取實例
                //那麼,若是在成功綁定以前,當前service就已經運行到這裏
                //就會出現數據丟失的狀況
                if (mIReceiveMessage != null) {
                    mIReceiveMessage.receiveMessage(mFollowModel.getData(), mAllModel.getData());
                }
            } else if (msg.what == HANDLER_LOCAL) { //收到本地須要修改的數據
                SocketEntity socketEntity = JsonUtils.fromJson((String) msg.obj, SocketEntity.class);
                mFollowModel.setDataNoAdd(socketEntity);
                mAllModel.setDataNoAdd(socketEntity);
                //考慮一下,由於ReceiveMessage須要在成功綁定以後才能獲取實例
                //那麼,若是在成功綁定以前,當前service就已經運行到這裏
                //就會出現數據丟失的狀況
                if (mIReceiveMessage != null) {
                    mIReceiveMessage.receiveMessage(mFollowModel.getData(), mAllModel.getData());
                }
            } else if (msg.what == HANDLER_DEBUG) {
                System.out.println(msg.obj.toString());
            } else if (msg.what == HANDLER_ERROR) {
                if (HOST == null) { //在掃描開始10秒後,結束到消息,判斷此時是否有掃描結果
                    Intent intent=new Intent(CONN_ERROR_ACTION);
                    mLocalBroadcastManager.sendBroadcast(intent);
                }
            }
        }
    };

    /**
     * 跟服務器確認首次鏈接
     * @param ip
     * @return
     */
    public Socket checkConn(String ip) {
        if (AppConfig.getInstance().isDebug()) {
            Message msg = mMsgHandler.obtainMessage();
            msg.what = HANDLER_DEBUG;
            msg.obj = "嘗試跟服務器socket通訊" + ip;
            msg.sendToTarget();
        }
        Socket socket = null;
        try {
            socket = new Socket();
            socket.connect(new InetSocketAddress(ip, PORT), 500);
            socket.setSoTimeout(1 * 1000);

            //獲取輸出流
            OutputStream os = socket.getOutputStream();
            //發送鏈接確認消息
            if (!socket.isClosed() && !socket.isOutputShutdown()) {
                String message = CHECK_CONN;
                os.write(message.getBytes());
                os.flush(); //刷新輸出流,使Server立刻收到該字符串
            }

            //獲取輸入流
            InputStream is = socket.getInputStream();
            byte[] buffer = new byte[1024 * 4];
            int length = 0;
            //接受鏈接確認消息
            while (!socket.isClosed() && !socket.isInputShutdown()
                    && ((length = is.read(buffer)) != -1)) {
                if (length > 0) {
                    String message = new String(Arrays.copyOf(buffer, length)).trim();
                    if (message.contains("\"cate\":8")) {
                        return socket;
                    } else if (message.contains("\"cate\":0")) {
                        Message msg = mMsgHandler.obtainMessage();
                        msg.what = HANDLER_SERVER;
                        msg.obj = message;
                        msg.sendToTarget();
                        return socket;
                    }
                }
            }
        } catch (SocketTimeoutException e) {
            if (AppConfig.getInstance().isDebug()) {
                Message msg = mMsgHandler.obtainMessage();
                msg.what = HANDLER_DEBUG;
                msg.obj = "socket服務器響應超時--->"+ip;
                msg.sendToTarget();
            }
        } catch (ConnectException e) {
            if (AppConfig.getInstance().isDebug()) {
                Message msg = mMsgHandler.obtainMessage();
                msg.what = HANDLER_DEBUG;
                msg.obj = "socket服務器請求超時--->"+ip;
                msg.sendToTarget();
            }
        } catch (InterruptedIOException e) {
            if (AppConfig.getInstance().isDebug()) {
                Message msg = mMsgHandler.obtainMessage();
                msg.what = HANDLER_DEBUG;
                msg.obj = "socket鏈接超時--->"+ip;
                msg.sendToTarget();
            }
        } catch (UnknownHostException e) {
            if (AppConfig.getInstance().isDebug()) {
                Message msg = mMsgHandler.obtainMessage();
                msg.what = HANDLER_DEBUG;
                msg.obj = "socket嘗試鏈接一個不存在的端口--->"+ip;
                msg.sendToTarget();
            }
        } catch (IOException e) {
            if (AppConfig.getInstance().isDebug()) {
                Message msg = mMsgHandler.obtainMessage();
                msg.what = HANDLER_DEBUG;
                msg.obj = "socket IOException--->"+ip;
                msg.sendToTarget();
            }
        }

        if (socket != null) {
            try {
                socket.close();
            } catch (IOException e) {
                if (AppConfig.getInstance().isDebug()) {
                    Message msg = mMsgHandler.obtainMessage();
                    msg.what = HANDLER_DEBUG;
                    msg.obj = "socket關閉失敗--->"+ip;
                    msg.sendToTarget();
                }
            }
            socket = null;
        }
        return null;
    }

    /**
     *跟服務器確認首次鏈接
     */
    class CheckConnRunnable implements Runnable {

        private String currentIp = null;
        private int ipSuff = 0; //ip後綴

        public CheckConnRunnable(String ip) { this(ip, 0); }

        public CheckConnRunnable(String ip, int ipSuff) {
            this.currentIp = ip;
            this.ipSuff = ipSuff;
        }

        @Override
        public void run() {
            if (ipSuff == 255) { // 在ip後綴爲1,即掃描開始後30秒,向消息隊列發送一次消息
                Message msgarg = new Message();
                msgarg.what = HANDLER_ERROR;
                mMsgHandler.sendMessageDelayed(msgarg, CONN_CHECK_RATE);
            }
            try {
                Socket socket = null;
                //向服務器發送驗證信息,若是驗證經過...
                if ((socket = checkConn(currentIp)) != null) {
                    if (AppConfig.getInstance().isDebug()) {
                        Message msg = mMsgHandler.obtainMessage();
                        msg.what = HANDLER_DEBUG;
                        msg.obj = "socket通訊成功"+currentIp;
                        msg.sendToTarget();
                    }
                    Intent intent = new Intent(CONN_CHECK_ACTION);
                    mLocalBroadcastManager.sendBroadcast(intent);
                    AppConfig.getInstance().setServerIp(currentIp);
                    HOST = currentIp;
                    socket.setSoTimeout(0);
                    initSocket(socket);
                } else {
                    if (AppConfig.getInstance().isDebug()) {
                        Message msg = mMsgHandler.obtainMessage();
                        msg.what = HANDLER_DEBUG;
                        msg.obj = "socket通訊失敗"+currentIp;
                        msg.sendToTarget();
                    }
                    if (ipSuff == 0) { //鏈接本地保存的服務器地址失敗,開始遍歷IP進行掃描
                        scanIpSegment();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 掃描局域網IP段
     */
    public void scanIpSegment(){
        System.out.println("開始遍歷局域網Ip段");
        String locAddrPref = NetUtils.getIpByWifi(this); //獲取本地ip前綴,好比192.168.1.
        if(locAddrPref == null || locAddrPref.equals("")) {
            Intent intent = new Intent(NO_CONN_ACTION);
            mLocalBroadcastManager.sendBroadcast(intent);
            return;
        }
        HOST = null;
        for (int suff = 1; suff < 256; suff++) {//建立256個線程分別去鏈接服務器
            ThreadManager.getInstance().addTask(
                    new CheckConnRunnable(locAddrPref + String.valueOf(suff), suff));
        }
    }

    /**
     * 釋放資源
     */
    public void release() {
        if (mHeartBeatHandler != null && heartBeatRunnable != null) {
            mHeartBeatHandler.removeCallbacks(heartBeatRunnable);
        }
        if (mReadThread != null) {
            mReadThread.release();
        }
        releaseLastSocket(mSocket);
    }

    /**
     * 中止整個service運行
     */
    public void stopWork() {
        release();
        ThreadManager.getInstance().closeThreadPool(); // 關閉線程池
        ActivityManager activityMgr= (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
        activityMgr.killBackgroundProcesses(getPackageName());
        android.os.Process.killProcess(android.os.Process.myPid());
        System.exit(0);
    }
}

 

package com.freer.infusion.module.service;
import android.app.ActivityManager;import android.app.PendingIntent;import android.app.Service;import android.content.Intent;import android.graphics.BitmapFactory;import android.os.Binder;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Parcelable;import android.support.v4.app.NotificationCompat;import android.support.v4.app.NotificationManagerCompat;import android.support.v4.content.ContextCompat;import android.support.v4.content.LocalBroadcastManager;import android.util.Log;
import com.freer.infusion.R;import com.freer.infusion.config.AppConfig;import com.freer.infusion.entity.SocketEntity;import com.freer.infusion.model.SocketDataModel;import com.freer.infusion.model.SocketDataProcess;import com.freer.infusion.module.main.MainActivity;import com.freer.infusion.util.JsonUtils;import com.freer.infusion.util.NetUtils;import com.freer.infusion.util.ScreenLockLocation;import com.freer.infusion.util.ThreadManager;import com.freer.infusion.util.ToastUtils;import com.google.gson.FieldAttributes;
import org.apache.http.conn.ConnectTimeoutException;
import java.io.IOException;import java.io.InputStream;import java.io.InterruptedIOException;import java.io.OutputStream;import java.io.Serializable;import java.lang.ref.WeakReference;import java.net.ConnectException;import java.net.Inet4Address;import java.net.InetAddress;import java.net.InetSocketAddress;import java.net.NetworkInterface;import java.net.Socket;import java.net.SocketException;import java.net.SocketTimeoutException;import java.net.UnknownHostException;import java.util.ArrayList;import java.util.Arrays;import java.util.Enumeration;import java.util.List;
/** * Created by 2172980000774 on 2016/5/12. */public class SocketService extends Service {
    /* handler消息標誌 */    private static final int HANDLER_DEBUG = 0; //Debug數據    private static final int HANDLER_SERVER = 1; //服務器數據    private static final int HANDLER_LOCAL = 2; //本地數據    private static final int HANDLER_ERROR = 3; //掃描服務器失敗
    private static final String CHECK_CONN = "{\"cate\":8,\"d\":[]}"; //鏈接確認    private static final String HEART_BEAT = "{\"cate\":9,\"d\":[]}"; //心跳檢測
    private static final long HEART_BEAT_RATE = 15 * 1000; //心跳檢測間隔時間    private static final long CONN_CHECK_RATE = 5 * 1000; //掃描服務器超時時間
    public static String HOST = null; //服務器IP地址    public static int PORT = 2020; //服務器端口號
    public static final String MESSAGE_ACTION="message_action";    public static final String HEART_BEAT_ACTION="heart_beat_action";    public static final String CONN_CHECK_ACTION = "conn_check_action";    public static final String CONN_ERROR_ACTION = "conn_error_action";    public static final String NO_CONN_ACTION = "no_conn_action";
    private ReadThread mReadThread;
    private LocalBroadcastManager mLocalBroadcastManager;
    private WeakReference<Socket> mSocket;
    private SocketDataProcess mSocketDataProcess = new SocketDataProcess();    private SocketDataModel mFollowModel = new SocketDataModel();    private SocketDataModel mAllModel = new SocketDataModel();
    private ScreenLockLocation mScreenLockLocation;
    /** For Heart Beat */    private long sendTime = 0L;    private Handler mHeartBeatHandler = new Handler();    private Runnable heartBeatRunnable = new Runnable() {
        @Override        public void run() {            if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) {                if (!sendMsg(null)) { //就發送一個心跳數據過去 若是發送失敗,就從新初始化一個socket                    // 發送失敗處理                    release();                    // 首先判斷本地是否服務器記錄,若是沒有則已經作過遍歷並鏈接失敗,直接通知用戶服務器鏈接失敗                    if (HOST == null) {                        Message sendFail = mMsgHandler.obtainMessage();                        sendFail.what = HANDLER_ERROR;                        sendFail.sendToTarget();                    } else {                        ThreadManager.getInstance().addTask(new CheckConnRunnable(HOST));//                        new Thread(new CheckConnRunnable(HOST)).start();                    }                }            }            mHeartBeatHandler.postDelayed(this, HEART_BEAT_RATE);        }    };
    /**     * 更新主界面數據接口     */    public interface IReceiveMessage {        void receiveMessage(List<SocketEntity> followBedList, List<SocketEntity> allBedList);    }    private IReceiveMessage mIReceiveMessage;
    public class SocketBinder extends Binder {        public boolean sendMessage(SocketEntity message) {            return sendMsg(message);        }
        public void setOnReveiveMessage(IReceiveMessage iReceiveMessage) {            mIReceiveMessage = iReceiveMessage;        }
        public void reStart() {            // 釋放以前的資源            release();            // 從新初始化socket            String ip = AppConfig.getInstance().getServerIp();            if (ip != null && !ip.equals("")) {                ThreadManager.getInstance().addTask(new CheckConnRunnable(ip));//                new Thread(new CheckConnRunnable(ip)).start();            } else {                if (HOST != null) {                    ThreadManager.getInstance().addTask(new CheckConnRunnable(HOST));//                    new Thread(new CheckConnRunnable(HOST)).start();                } else {                    scanIpSegment();                }            }        }    }
    /**     * 開始鏈接服務器     */    public void startWork() {        String ip = AppConfig.getInstance().getServerIp();        if (ip != null && !ip.equals("")) {//            new Thread(new CheckConnRunnable(ip)).start();            ThreadManager.getInstance().addTask(new CheckConnRunnable(ip));        } else {            scanIpSegment();        }    }
    public SocketBinder mSocketBinder;
    @Override    public IBinder onBind(Intent arg0) {        return mSocketBinder;    }
    @Override    public void onCreate() {        super.onCreate();        mScreenLockLocation = new ScreenLockLocation(this);        mScreenLockLocation.start();
        Intent intent =  new Intent(this, MainActivity.class);        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        startForeground(1,                new NotificationCompat.Builder(this)                        .setSmallIcon(R.drawable.ic_launcher)                        .setContentTitle(SocketService.this.getString(R.string.navi_title))                        .setContentText(SocketService.this.getString(R.string.navi_content))                        .setShowWhen(false)                        .setOngoing(true)                        .setContentIntent(PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT))                        .build());
        mSocketBinder = new SocketBinder();        mLocalBroadcastManager=LocalBroadcastManager.getInstance(this);
//        new InitSocketThread().start();        startWork();//        ThreadManager.getInstance().addTask(new CheckConnRunnable("192.168.1.3"));    }
    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.e("SocketService", "onStartCommand");        return super.onStartCommand(intent, flags, startId);    }
    @Override    public void onDestroy() {        Log.e("SocketService", "onDestroy");        mScreenLockLocation.stop();        stopForeground(true);        stopWork();        super.onDestroy();    }
    public boolean sendMsg(SocketEntity msg) {        if (null == mSocket || null == mSocket.get()) {            return false;        }        Socket soc = mSocket.get();        try {            if (!soc.isClosed() && !soc.isOutputShutdown()) {                OutputStream os = soc.getOutputStream();                // 若是爲null,說明是心跳檢測,不然就是本地主動設置的數據                String message =                        msg == null ?                                HEART_BEAT : "{\"cate\":0,\"d\":["+msg.toString()+"]}";                os.write(message.getBytes());                os.flush();                //發送成功處理                sendTime = System.currentTimeMillis(); //每次發送成數據,就改一下最後成功發送的時間,節省心跳間隔時間                if (msg != null) { //確認是本地主動修改發送給服務器的數據                    Message sendSuccess = mMsgHandler.obtainMessage();                    sendSuccess.what = HANDLER_LOCAL;                    sendSuccess.obj = msg.toString();                    sendSuccess.sendToTarget();                }                return true;            }        } catch (IOException e) {            System.out.println("發送失敗");        }        return false;    }
    private void initSocket() { // 初始化Socket        try {            Socket so = new Socket(HOST, PORT);            mSocket = new WeakReference<>(so);            mReadThread = new ReadThread(so);            mReadThread.start();            mHeartBeatHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);//初始化成功後,就準備發送心跳包        } catch (UnknownHostException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }    }
    /**     * 在遍歷ip以後,第一次鏈接調用     * @param socket     */    private void initSocket(Socket socket) {        mSocket = new WeakReference<Socket>(socket);        mReadThread = new ReadThread(socket);        mReadThread.start();        mHeartBeatHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE); // 初始化成功後,就準備發送心跳包    }
    private void releaseLastSocket(WeakReference<Socket> mSocket) {        try {            if (null != mSocket) {                Socket sk = mSocket.get();                if (sk != null && !sk.isClosed()) {                    sk.close();                }                sk = null;                mSocket = null;            }        } catch (IOException e) {            e.printStackTrace();        }    }
    class InitSocketThread extends Thread {        @Override        public void run() {            super.run();            initSocket();        }    }
    // Thread to read content from Socket    class ReadThread extends Thread {        private WeakReference<Socket> weakSocket;        private boolean isStart = true;
        public ReadThread(Socket socket) {            weakSocket = new WeakReference<Socket>(socket);        }
        public void release() {            isStart = false;            releaseLastSocket(weakSocket);        }
        @Override        public void run() {            super.run();            Socket socket = weakSocket.get();            receiveMsg(socket, isStart);        }    }
    public void receiveMsg(Socket socket, boolean isStart) {        if (null != socket) {            try {                InputStream is = socket.getInputStream();                byte[] buffer = new byte[1024 * 4];                int length = 0;                while (!socket.isClosed() && !socket.isInputShutdown()                        && isStart && ((length = is.read(buffer)) != -1)) {                    if (length > 0) {                        String message = new String(Arrays.copyOf(buffer,                                length)).trim();                        System.out.println("收到Socket服務器回覆");                        //收到服務器過來的消息,就經過Broadcast發送出去                        if(message.contains("\"cate\":9")){//處理心跳回復                            System.out.println("當前回覆爲心跳檢測");//                            Intent intent=new Intent(HEART_BEAT_ACTION);//                            mLocalBroadcastManager.sendBroadcast(intent);                        }else if (message.contains("\"cate\":0")){                            System.out.println("當前回覆爲其餘回覆");                            //其餘消息回覆                            Message msg = mMsgHandler.obtainMessage();                            msg.what = HANDLER_SERVER;                            msg.obj = message;                            msg.sendToTarget();                        }                    }                }            } catch (IOException e) {                e.printStackTrace();            }        }    }
    /**     * 經過回調的方式通知activity     * 經過handler從子線程傳遞數據到主線程中     */    private Handler mMsgHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            if (msg.what == HANDLER_SERVER) { //收到服務器傳遞的數據                sendTime = System.currentTimeMillis(); //每一次成功接收到服務器主動發送的消息,更新時間                if (msg!=null && msg.obj != null) {                    System.out.println("收到原始數據"+msg.obj.toString());                }                String data = (String) msg.obj;//                mSocketDataProcess.processData(data);                mFollowModel.processData(data, true);                mAllModel.processData(data, false);                //考慮一下,由於ReceiveMessage須要在成功綁定以後才能獲取實例                //那麼,若是在成功綁定以前,當前service就已經運行到這裏                //就會出現數據丟失的狀況                if (mIReceiveMessage != null) {                    mIReceiveMessage.receiveMessage(mFollowModel.getData(), mAllModel.getData());                }            } else if (msg.what == HANDLER_LOCAL) { //收到本地須要修改的數據                SocketEntity socketEntity = JsonUtils.fromJson((String) msg.obj, SocketEntity.class);                mFollowModel.setDataNoAdd(socketEntity);                mAllModel.setDataNoAdd(socketEntity);                //考慮一下,由於ReceiveMessage須要在成功綁定以後才能獲取實例                //那麼,若是在成功綁定以前,當前service就已經運行到這裏                //就會出現數據丟失的狀況                if (mIReceiveMessage != null) {                    mIReceiveMessage.receiveMessage(mFollowModel.getData(), mAllModel.getData());                }            } else if (msg.what == HANDLER_DEBUG) {                System.out.println(msg.obj.toString());            } else if (msg.what == HANDLER_ERROR) {                if (HOST == null) { //在掃描開始10秒後,結束到消息,判斷此時是否有掃描結果                    Intent intent=new Intent(CONN_ERROR_ACTION);                    mLocalBroadcastManager.sendBroadcast(intent);                }            }        }    };
    /**     * 跟服務器確認首次鏈接     * @param ip     * @return     */    public Socket checkConn(String ip) {        if (AppConfig.getInstance().isDebug()) {            Message msg = mMsgHandler.obtainMessage();            msg.what = HANDLER_DEBUG;            msg.obj = "嘗試跟服務器socket通訊" + ip;            msg.sendToTarget();        }        Socket socket = null;        try {            socket = new Socket();            socket.connect(new InetSocketAddress(ip, PORT), 500);            socket.setSoTimeout(1 * 1000);
            //獲取輸出流            OutputStream os = socket.getOutputStream();            //發送鏈接確認消息            if (!socket.isClosed() && !socket.isOutputShutdown()) {                String message = CHECK_CONN;                os.write(message.getBytes());                os.flush(); //刷新輸出流,使Server立刻收到該字符串            }
            //獲取輸入流            InputStream is = socket.getInputStream();            byte[] buffer = new byte[1024 * 4];            int length = 0;            //接受鏈接確認消息            while (!socket.isClosed() && !socket.isInputShutdown()                    && ((length = is.read(buffer)) != -1)) {                if (length > 0) {                    String message = new String(Arrays.copyOf(buffer, length)).trim();                    if (message.contains("\"cate\":8")) {                        return socket;                    } else if (message.contains("\"cate\":0")) {                        Message msg = mMsgHandler.obtainMessage();                        msg.what = HANDLER_SERVER;                        msg.obj = message;                        msg.sendToTarget();                        return socket;                    }                }            }        } catch (SocketTimeoutException e) {            if (AppConfig.getInstance().isDebug()) {                Message msg = mMsgHandler.obtainMessage();                msg.what = HANDLER_DEBUG;                msg.obj = "socket服務器響應超時--->"+ip;                msg.sendToTarget();            }        } catch (ConnectException e) {            if (AppConfig.getInstance().isDebug()) {                Message msg = mMsgHandler.obtainMessage();                msg.what = HANDLER_DEBUG;                msg.obj = "socket服務器請求超時--->"+ip;                msg.sendToTarget();            }        } catch (InterruptedIOException e) {            if (AppConfig.getInstance().isDebug()) {                Message msg = mMsgHandler.obtainMessage();                msg.what = HANDLER_DEBUG;                msg.obj = "socket鏈接超時--->"+ip;                msg.sendToTarget();            }        } catch (UnknownHostException e) {            if (AppConfig.getInstance().isDebug()) {                Message msg = mMsgHandler.obtainMessage();                msg.what = HANDLER_DEBUG;                msg.obj = "socket嘗試鏈接一個不存在的端口--->"+ip;                msg.sendToTarget();            }        } catch (IOException e) {            if (AppConfig.getInstance().isDebug()) {                Message msg = mMsgHandler.obtainMessage();                msg.what = HANDLER_DEBUG;                msg.obj = "socket IOException--->"+ip;                msg.sendToTarget();            }        }
        if (socket != null) {            try {                socket.close();            } catch (IOException e) {                if (AppConfig.getInstance().isDebug()) {                    Message msg = mMsgHandler.obtainMessage();                    msg.what = HANDLER_DEBUG;                    msg.obj = "socket關閉失敗--->"+ip;                    msg.sendToTarget();                }            }            socket = null;        }        return null;    }
    /**     *跟服務器確認首次鏈接     */    class CheckConnRunnable implements Runnable {
        private String currentIp = null;        private int ipSuff = 0; //ip後綴
        public CheckConnRunnable(String ip) { this(ip, 0); }
        public CheckConnRunnable(String ip, int ipSuff) {            this.currentIp = ip;            this.ipSuff = ipSuff;        }
        @Override        public void run() {            if (ipSuff == 255) { // 在ip後綴爲1,即掃描開始後30秒,向消息隊列發送一次消息                Message msgarg = new Message();                msgarg.what = HANDLER_ERROR;                mMsgHandler.sendMessageDelayed(msgarg, CONN_CHECK_RATE);            }            try {                Socket socket = null;                //向服務器發送驗證信息,若是驗證經過...                if ((socket = checkConn(currentIp)) != null) {                    if (AppConfig.getInstance().isDebug()) {                        Message msg = mMsgHandler.obtainMessage();                        msg.what = HANDLER_DEBUG;                        msg.obj = "socket通訊成功"+currentIp;                        msg.sendToTarget();                    }                    Intent intent = new Intent(CONN_CHECK_ACTION);                    mLocalBroadcastManager.sendBroadcast(intent);                    AppConfig.getInstance().setServerIp(currentIp);                    HOST = currentIp;                    socket.setSoTimeout(0);                    initSocket(socket);                } else {                    if (AppConfig.getInstance().isDebug()) {                        Message msg = mMsgHandler.obtainMessage();                        msg.what = HANDLER_DEBUG;                        msg.obj = "socket通訊失敗"+currentIp;                        msg.sendToTarget();                    }                    if (ipSuff == 0) { //鏈接本地保存的服務器地址失敗,開始遍歷IP進行掃描                        scanIpSegment();                    }                }            } catch (IOException e) {                e.printStackTrace();            }        }    }
    /**     * 掃描局域網IP段     */    public void scanIpSegment(){        System.out.println("開始遍歷局域網Ip段");        String locAddrPref = NetUtils.getIpByWifi(this); //獲取本地ip前綴,好比192.168.1.        if(locAddrPref == null || locAddrPref.equals("")) {            Intent intent = new Intent(NO_CONN_ACTION);            mLocalBroadcastManager.sendBroadcast(intent);            return;        }        HOST = null;        for (int suff = 1; suff < 256; suff++) {//建立256個線程分別去鏈接服務器            ThreadManager.getInstance().addTask(                    new CheckConnRunnable(locAddrPref + String.valueOf(suff), suff));        }    }
    /**     * 釋放資源     */    public void release() {        if (mHeartBeatHandler != null && heartBeatRunnable != null) {            mHeartBeatHandler.removeCallbacks(heartBeatRunnable);        }        if (mReadThread != null) {            mReadThread.release();        }        releaseLastSocket(mSocket);    }
    /**     * 中止整個service運行     */    public void stopWork() {        release();        ThreadManager.getInstance().closeThreadPool(); // 關閉線程池        ActivityManager activityMgr= (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);        activityMgr.killBackgroundProcesses(getPackageName());        android.os.Process.killProcess(android.os.Process.myPid());        System.exit(0);    }}java

相關文章
相關標籤/搜索