由于移动设备的网络的复杂性,经常会出现网络断开,如果没有心跳包的检测,客户端只会在需要发送数据的时候才知道自己已经断线,会延误,甚至丢失服务器发送过来的数据。一下简单建立一个带有心跳检测的SocketDemo。
Android 后台Servevice
package org.feng.sockettest.server;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.lang.ref.WeakReference;import java.net.Socket;import java.net.UnknownHostException;import java.util.Arrays;import android.app.Service;import android.content.Intent;import android.os.Handler;import android.os.IBinder;import android.os.RemoteException;import android.support.v4.content.LocalBroadcastManager;import android.util.Log;public class BackService extends Service { private static final String TAG = "BackService"; private static final long HEART_BEAT_RATE = 3 * 1000; public static final String HOST = "192.168.1.101";// "192.168.1.21";// public static final int PORT = 9800; public static final String MESSAGE_ACTION="org.feng.message_ACTION"; public static final String HEART_BEAT_ACTION="org.feng.heart_beat_ACTION"; private ReadThread mReadThread; private LocalBroadcastManager mLocalBroadcastManager; private WeakReferencemSocket; // For heart Beat private Handler mHandler = new Handler(); private Runnable heartBeatRunnable = new Runnable() { @Override public void run() { if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) { boolean isSuccess = sendMsg("");//就发送一个\r\n过去 如果发送失败,就重新初始化一个socket if (!isSuccess) { mHandler.removeCallbacks(heartBeatRunnable); mReadThread.release(); releaseLastSocket(mSocket); new InitSocketThread().start(); } } mHandler.postDelayed(this, HEART_BEAT_RATE); } }; private long sendTime = 0L; private IBackService.Stub iBackService = new IBackService.Stub() { @Override public boolean sendMessage(String message) throws RemoteException { return sendMsg(message); } }; @Override public IBinder onBind(Intent arg0) { return iBackService; } @Override public void onCreate() { super.onCreate(); new InitSocketThread().start(); mLocalBroadcastManager=LocalBroadcastManager.getInstance(this); } public boolean sendMsg(String msg) { if (null == mSocket || null == mSocket.get()) { return false; } Socket soc = mSocket.get(); try { if (!soc.isClosed() && !soc.isOutputShutdown()) { OutputStream os = soc.getOutputStream(); String message = msg + "\r\n"; os.write(message.getBytes()); os.flush(); sendTime = System.currentTimeMillis();//每次发送成数据,就改一下最后成功发送的时间,节省心跳间隔时间 } else { return false; } } catch (IOException e) { e.printStackTrace(); return false; } return true; } private void initSocket() {//初始化Socket try { Socket so = new Socket(HOST, PORT); mSocket = new WeakReference (so); mReadThread = new ReadThread(so); mReadThread.start(); mHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);//初始化成功后,就准备发送心跳包 } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private void releaseLastSocket(WeakReference mSocket) { try { if (null != mSocket) { Socket sk = mSocket.get(); if (!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 mWeakSocket; private boolean isStart = true; public ReadThread(Socket socket) { mWeakSocket = new WeakReference (socket); } public void release() { isStart = false; releaseLastSocket(mWeakSocket); } @Override public void run() { super.run(); Socket socket = mWeakSocket.get(); 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(); Log.e(TAG, message); //收到服务器过来的消息,就通过Broadcast发送出去 if(message.equals("ok")){//处理心跳回复 Intent intent=new Intent(HEART_BEAT_ACTION); mLocalBroadcastManager.sendBroadcast(intent); }else{ //其他消息回复 Intent intent=new Intent(MESSAGE_ACTION); intent.putExtra("message", message); mLocalBroadcastManager.sendBroadcast(intent); } } } } catch (IOException e) { e.printStackTrace(); } } } }}
在Activity中发送以及接收数据:
package org.feng.sockettest;import java.lang.ref.WeakReference;import org.feng.sockettest.server.BackService;import org.feng.sockettest.server.IBackService;import android.app.Activity;import android.content.BroadcastReceiver;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.support.v4.content.LocalBroadcastManager;import android.view.View;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity { private static final String TAG = "MainActivity"; private IBackService iBackService; private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { iBackService = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { iBackService = IBackService.Stub.asInterface(service); } }; private TextView mResultText; private EditText mEditText; private Intent mServiceIntent; class MessageBackReciver extends BroadcastReceiver { private WeakReferencetextView; public MessageBackReciver(TextView tv) { textView = new WeakReference (tv); } @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); TextView tv = textView.get(); if (action.equals(BackService.HEART_BEAT_ACTION)) { if (null != tv) { tv.setText("Get a heart heat"); } } else { String message = intent.getStringExtra("message"); tv.setText(message); } }; } private MessageBackReciver mReciver; private IntentFilter mIntentFilter; private LocalBroadcastManager mLocalBroadcastManager; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mLocalBroadcastManager = LocalBroadcastManager.getInstance(this); mResultText = (TextView) findViewById(R.id.resule_text); mEditText = (EditText) findViewById(R.id.content_edit); mReciver = new MessageBackReciver(mResultText); mServiceIntent = new Intent(this, BackService.class); mIntentFilter = new IntentFilter(); mIntentFilter.addAction(BackService.HEART_BEAT_ACTION); mIntentFilter.addAction(BackService.MESSAGE_ACTION); } @Override protected void onStart() { super.onStart(); mLocalBroadcastManager.registerReceiver(mReciver, mIntentFilter); bindService(mServiceIntent, conn, BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); unbindService(conn); mLocalBroadcastManager.unregisterReceiver(mReciver); } public void onClick(View view) { switch (view.getId()) { case R.id.send: String content = mEditText.getText().toString(); try { boolean isSend = iBackService.sendMessage(content);//Send Content by socket Toast.makeText(this, isSend ? "success" : "fail", Toast.LENGTH_SHORT).show(); mEditText.setText(""); } catch (RemoteException e) { e.printStackTrace(); } break; default: break; } }}
完整项目带服务器段代码的见: