原地址:http://blog.csdn.net/qingzi635533/article/details/24302175
最近公司项目要做一个同步功能,需要涉及到服务器与客户端的长连接,当时头脑里第一联想到的就是Socket啊,虽然Socket自己当时也了解过一点,但是长连接还是没做过啊,更何况心跳包,个个都是以前没有接触过的,于是就在网上找资料学习,终于功夫不负有心人找到了对应的资料,也实现了功能,下面废话不多说直接上代码吧。
首先是心跳包Service
package org.feng.sockettest.server;
import android.annotation.SuppressLint;
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;
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;
/**
* 心跳包服务
*/
public class BackService extends Service {
private static final String TAG = "BackService";
/**心跳间隔*/
private static final long HEART_BEAT_RATE = 9 * 1000;
/**IP地址*/
public static final String HOST = "192.168.10.241";
/**端口号*/
public static final int PORT = 30000;
/**其他消息的过滤器*/
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 WeakReference<Socket> mSocket;
//通过Handler实现Socket心跳包机制
private Handler mHandler = new Handler();
private Runnable heartBeatRunnable = new Runnable() {
@Override
public void run() {
//判断当前时间 和 上次发送心跳包的时间 间隔是否大于等于 设置的心跳包间隔,如果大于或等于就发送心跳包
if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) {
boolean isSuccess = sendMsg("alive");//就发送一个"alive"过去 如果发送失败,就重新初始化一个socket
if (!isSuccess) {
mHandler.removeCallbacks(heartBeatRunnable);
mReadThread.release();
releaseLastSocket(mSocket);
new InitSocketThread().start();
}
}
//这里是实现心跳包保持
mHandler.postDelayed(this, HEART_BEAT_RATE);
}
};
private long sendTime = 0L; //初始化发送心跳包时间
//收到前台信息的处理,通过AIDL回调,发送给服务器
private IBackService.Stub iBackService = new IBackService.Stub() {
@Override
public boolean sendMessage(String message) throws RemoteException {
return sendMsg(message);
}
};
@Override
public IBinder onBind(Intent arg0) {
//绑定服务,让服务于AIDL进行关联
return iBackService;
}
@Override
public void onCreate() {
super.onCreate();
new InitSocketThread().start(); //当服务启动的时候,初始化Socket
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<Socket>(so);
mReadThread = new ReadThread(so);
mReadThread.start();
mHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);//初始化成功后,就准备发送心跳包
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**释放最后的Socket引用,如果连接失败,需要关闭并且释放之前的Socket,因为一但连接失败就会重新连接,
* 重新连接就会创建出新的Socket,如果之前的Socket不释放,
* 一但经历多次的重新连接后,就会造成内存泄漏,这也是使用软引用的原因
*/
private void releaseLastSocket(WeakReference<Socket> mSocket) {
try {
if (null != mSocket) {
Socket sk = mSocket.get();
if (!sk.isClosed()) {
sk.close();
}
sk = null;
mSocket = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**用于初始化Socket*/
class InitSocketThread extends Thread {
@Override
public void run() {
super.run();
initSocket();
}
}
//读取服务器发送过来的Socket
class ReadThread extends Thread {
private WeakReference<Socket> mWeakSocket;
private boolean isStart = true;
public ReadThread(Socket socket) {
mWeakSocket = new WeakReference<Socket>(socket);
}
public void release() {
isStart = false;
releaseLastSocket(mWeakSocket);
}
@SuppressLint({"NewApi", "LocalSuppress"})
@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("alive")){//处理心跳回复
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 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.support.v4.content.LocalBroadcastManager;
import android.widget.TextView;
import org.feng.sockettest.server.BackService;
import org.feng.sockettest.server.IBackService;
import java.lang.ref.WeakReference;
public class MainActivity extends Activity {
private IBackService iBackService; //发送消息的回调接口
private ServiceConnection conn = new ServiceConnection() { //服务连接监听
@Override
public void onServiceDisconnected(ComponentName name) {
iBackService = null;//如果服务已经断开,关闭aidl回调
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//如果服务成功连接,则初始化aidl接口,与服务进行绑定
iBackService = IBackService.Stub.asInterface(service);
}
};
private TextView mResultText; //显示服务器返回的消息
private Intent mServiceIntent;
//创建一个广播接收者,用于响应服务器发送过来的消息,实时刷新UI
class MessageBackReceiver extends BroadcastReceiver {
private WeakReference<TextView> textView;
public MessageBackReceiver(TextView tv) {
textView = new WeakReference<TextView>(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 MessageBackReceiver mReceiver;
/**广播过滤器*/
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);
/**实例化广播接收者*/
mReceiver = new MessageBackReceiver(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(mReceiver, mIntentFilter);
/**绑定服务*/
bindService(mServiceIntent, conn, BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
/**当应用处于暂停状态,解绑服务*/
unbindService(conn);
/**注销广播*/
mLocalBroadcastManager.unregisterReceiver(mReceiver);
}
}
最后是AIDL文件,这个可以省略,可以自己使用接口实现
package org.feng.sockettest.server;
interface IBackService{
boolean sendMessage(String message);
}