下面給出一個簡單的小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();
}
}
}
}