socket心跳檢測和重連小demo

        有時候我們的程序要求socket一直保持連接,並且希望在socket斷開以後能夠重新連接,這個時候就需要用到心跳機制,所謂心跳機制,最簡單的做法就是客戶端每隔一段時間向服務端發送數據包,爲了節約資源我們很多時候發送空數據就好,如果數據不能發送成功說明socket已經斷開,這個時候就需要根據具體需求釋放資源和重新連接了。

        下面給出一個簡單的小demo 

 /**
     * 連接服務端
     */
    private void connectToServer() {
        Thread connectThread = new Thread(new Runnable() {
            public void run() {
                try {
                    mSocket = new Socket();
                    mSocket.connect(
                            new InetSocketAddress(SOCKET_HOST, SOCKET_PORT));

                    Log.e(TAG, "連接成功  " + SOCKET_HOST);
                    mDataOutputStream = new DataOutputStream(
                            mSocket.getOutputStream());
                    
                    // 開啓線程負責讀取服務端數據
                    mReadThread = new SocketReadThread();
                    mReadThread.start();
                    
                    // 心跳檢測,檢測socket是否連接
                    mHandler.postDelayed(mHeartBeatRunnable, HEART_BEAT_RATE);
                } catch (UnknownHostException e) {
                    Log.e(TAG, "連接失敗  ");
                    e.printStackTrace();
                } catch (IOException e) {
                    Log.e(TAG, "連接失敗  ");
                    e.printStackTrace();
                }
            }
        });
        connectThread.start();
    }

         上述方法負責創建新的socket實例和開啓心跳檢測,其中比較重要的代碼是
          mHandler.postDelayed(mHeartBeatRunnable, HEART_BEAT_RATE);
          這裏的HEART_BEAT_RATE是一個int常量,表示心跳間隔,mHeartBeatRunnableze則負責心跳檢測

// 心跳機制
    private SocketReadThread mReadThread;
    private static final long HEART_BEAT_RATE = 4 * 1000;
    private long sendTime = 0L;
    private Runnable mHeartBeatRunnable = new Runnable() {

        @Override
        public void run() {
            if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) {//每隔4秒檢測一次
                boolean isSuccess = sendHeartBeatMsg("");
                if (!isSuccess) {
                    Log.i(TAG, "連接已斷開,正在重連……");
                    mHandler.removeCallbacks(mHeartBeatRunnable);// 移除線程,重連時保證該線程已停止上次調用時的工作
                    mReadThread.release();//釋放SocketReadThread線程資源
                    releaseLastSocket();
                    connectToServer();// 再次調用connectToServer方法,連接服務端
                }
            }
            mHandler.postDelayed(this, HEART_BEAT_RATE);
        }
    };
    /**
     * 發送心跳包
     * 
     * @param msg
     * @return
     */
    public boolean sendHeartBeatMsg(String msg) {
        if (null == mSocket) {
            return false;
        }
        try {
            if (!mSocket.isClosed() && !mSocket.isOutputShutdown()) {
                String message = msg + "\r\n";
                mDataOutputStream.write(message.getBytes());
                mDataOutputStream.flush();
                sendTime = System.currentTimeMillis();
            } else {
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

        上述方法是心跳檢測的主要方法,調用sendHeartBeatMsg()發送數據到服務端,該方法稍後給出。如果檢測到連接斷開,則釋放各種資源,重新連接。如果連接沒有斷開則繼續檢測,非常簡單的邏輯

/**
  * 斷開連接
  *
  */
    private void releaseLastSocket() {
        try {
            if (null != mSocket) {
                if (!mSocket.isClosed()) {
                    mSocket.close();
                }
            }
            mSocket = null;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

         最後給出SocketReadThread線程,這個線程負責讀取服務端發送過來的數據,和心跳機制無關,但在心跳機制中重連處理時,一定要釋放它的資源。

public class SocketReadThread extends Thread {

        private static final String TAG = "SocketThread";
        private volatile boolean mStopThread = false;
        public void release() {
            mStopThread = true;
            releaseLastSocket();
        }
        @Override
        public void run() {
            DataInputStream mInputStream = null;
            try {
                mInputStream = new DataInputStream(mSocket.getInputStream());
                Logger.d(TAG, "SocketThread running!");
                while (!mStopThread) { 
                    String resultStr = mInputStream.readUTF();
                    handleStringMsg(resultStr);
                }
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    mSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (mInputStream != null) {
                    try {
                        mInputStream.close();
                        mInputStream = null;
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章