Android socket通信的长连接与心跳检测

在Android开发中,我们可能需要和服务器保持连接不断开,这时需要用到socket通信的长连接,并且定时发送消息检测是否是连接状态——心跳检测。
我们需要一个客户端和一个服务器端的demo,现在我就贴出重要代码,主要是android客户端的,服务器端的demo供大家下载。
首先我们需要新建一个BackService类来继承Service:

package com.example.sockettest;  

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.annotation.SuppressLint;  
import android.app.Service;  
import android.content.Intent;  
import android.os.Handler;  
import android.os.IBinder;  
import android.os.RemoteException;  
import android.util.Log;  

public class BackService extends Service {  
    private static final String TAG = "BackService";  
    /** 心跳检测时间  */  
    private static final long HEART_BEAT_RATE = 3 * 1000;  
    /** 主机IP地址  */  
    private static final String HOST = "192.168.1.104";  
    /** 端口号  */  
    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 long sendTime = 0L;  

    /** 弱引用 在引用对象的同时允许对垃圾对象进行回收  */  
    private WeakReference<Socket> mSocket;  

    private ReadThread mReadThread;  

    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 (IBinder) iBackService;  
    }  

    @Override  
    public void onCreate() {  
        super.onCreate();  
        new InitSocketThread().start();  
    }  

    // 发送心跳包  
    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);  
        }  
    };  

    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();// 每次发送成功数据,就改一下最后成功发送的时间,节省心跳间隔时间  
                Log.i(TAG, "发送成功的时间:" + sendTime);  
            } else {  
                return false;  
            }  
        } catch (IOException e) {  
            e.printStackTrace();  
            return false;  
        }  
        return true;  
    }  

    // 初始化socket  
    private void initSocket() throws UnknownHostException, IOException {  
        Socket socket = new Socket(HOST, PORT);  
        mSocket = new WeakReference<Socket>(socket);  
        mReadThread = new ReadThread(socket);  
        mReadThread.start();  
        mHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);// 初始化成功后,就准备发送心跳包  
    }  

    // 释放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();  
        }  
    }  

    class InitSocketThread extends Thread {  
        @Override  
        public void run() {  
            super.run();  
            try {  
                initSocket();  
            } catch (UnknownHostException e) {  
                e.printStackTrace();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
    }  

    public 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")  
        @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.i(TAG, "收到服务器发送来的消息:"+message);   
                            // 收到服务器过来的消息,就通过Broadcast发送出去    
                            if (message.equals("ok")) {// 处理心跳回复  
                                Intent intent = new Intent(HEART_BEAT_ACTION);  
                                sendBroadcast(intent);  
                            } else {  
                                // 其他消息回复  
                                Intent intent = new Intent(MESSAGE_ACTION);  
                                intent.putExtra("message", message);  
                                sendBroadcast(intent);  
                            }  
                        }   
                    }  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
    }  
}  

关键代码已经注释了,相信大家应该可以看懂。在这个类中关联了一个IBackService的类,新建一个IBackService.aidl。对,没错,就是新建一个IBackService.aidl,关于aidl的知识请查阅相关文档。代码如下:

package com.example.sockettest;  
interface IBackService{  
    boolean sendMessage(String message);  
}  

现在就是MainActivity了,这就是一个activity,接收广播,改变UI,就不多说了:

package com.example.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.os.RemoteException;  
import android.util.Log;  
import android.view.View;  
import android.view.View.OnClickListener;  
import android.widget.Button;  
import android.widget.EditText;  
import android.widget.TextView;  
import android.widget.Toast;  

public class MainActivity extends Activity {  
    private static final String TAG = "MainActivity";  

    private Intent mServiceIntent;  
    private IBackService iBackService;  
    private TextView tv;  
    private EditText et;  
    private Button btn;  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  

        initViews();  
        initData();  
    }  

    private void initViews() {  
        tv = (TextView) findViewById(R.id.tv);  
        et = (EditText) findViewById(R.id.editText1);  
        btn = (Button) findViewById(R.id.button1);  
    }  

    private void initData() {  
        mServiceIntent = new Intent(this, BackService.class);  
        btn.setOnClickListener(new OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                String string = et.getText().toString().trim();  
                Log.i(TAG, string);  
                try {  
                    Log.i(TAG, "是否为空:" + iBackService);  
                    if (iBackService == null) {  
                        Toast.makeText(getApplicationContext(),  
                                "没有连接,可能是服务器已断开", Toast.LENGTH_SHORT).show();  
                    } else {  
                        boolean isSend = iBackService.sendMessage(string);  
                        Toast.makeText(MainActivity.this,  
                                isSend ? "success" : "fail", Toast.LENGTH_SHORT)  
                                .show();  
                        et.setText("");  
                    }  
                } catch (RemoteException e) {  
                    e.printStackTrace();  
                }  
            }  
        });  
    }  

    @Override  
    protected void onStart() {  
        super.onStart();  
        bindService(mServiceIntent, conn, BIND_AUTO_CREATE);  
        // 开始服务  
        registerReceiver();  
    }  

    @Override  
    protected void onResume() {  
        super.onResume();  
        // 注册广播 最好在onResume中注册  
        // registerReceiver();  
    }  

    @Override  
    protected void onPause() {  
        super.onPause();  
        // 注销广播 最好在onPause上注销  
        unregisterReceiver(mReceiver);  
        // 注销服务  
        unbindService(conn);  
    }  

    // 注册广播  
    private void registerReceiver() {  
        IntentFilter intentFilter = new IntentFilter();  
        intentFilter.addAction(BackService.HEART_BEAT_ACTION);  
        intentFilter.addAction(BackService.MESSAGE_ACTION);  
        registerReceiver(mReceiver, intentFilter);  
    }  

    private BroadcastReceiver mReceiver = new BroadcastReceiver() {  
        @Override  
        public void onReceive(Context context, Intent intent) {  
            String action = intent.getAction();  
            // 消息广播  
            if (action.equals(BackService.MESSAGE_ACTION)) {  
                String stringExtra = intent.getStringExtra("message");  
                tv.setText(stringExtra);  
            } else if (action.equals(BackService.HEART_BEAT_ACTION)) {// 心跳广播  
                tv.setText("正常心跳");  
            }  
        }  
    };  

    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);  
        }  
    };  
}  

好了,我们可以运行项目了。

Demo


  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值