转载自: http://blog.csdn.net/u011791526/article/details/53536403
有时候我们的程序要求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();
- }
- }
- }
- }