Socket跨进程长连接

public class SocketService extends Service {
    private static final String TAG = "SocketService";
    private static final long HEART_BEAT_RATE = 60 * 1000;
    private static final long RECONNECT_RATE = 3000;  //3秒 重连

    private ReadThread mReadThread;


    private WeakReference<Socket> mSocket;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch ( msg.what){
                case Constants.ERR_CODE_FAIL:
                    ToastUtil.showCenterToast(getApplicationContext(),"控制失败!");
                    break;
                case Constants.ERR_CODE_OFFLINE:
                    ToastUtil.showCenterToast(getApplicationContext(),"设备离线!");
                    break;
                case Constants.ERR_CODE_TIMEOUT:
                    ToastUtil.showCenterToast(getApplicationContext(),"超时!");
                    break;
                case Constants.ERR_CODE_CNT:
                    break;
                default:
                    break;
            }
        }
    };
    /**
     * 心跳检测步骤:
     1.客户端每隔一个时间间隔发生一个探测包给服务器
     2.客户端发包时启动一个超时定时器
     3.服务器端接收到检测包,应该回应一个包
     4.如果客户机收到服务器的应答包,则说明服务器正常,删除超时定时器
     5.如果客户端的超时定时器超时,依然没有收到应答包,则说明服务器挂了
     */
    private Runnable heartBeatRunnable = new Runnable() {

        @Override
        public void run() {
            if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) {
                boolean isSuccess = sendHeartBeat();//就发送一个\r\n过去 如果发送失败,就重新初始化一个socket
                if (!isSuccess) {
                    mHandler.removeCallbacks(heartBeatRunnable);
                    if(null!=mReadThread){
                        mReadThread.release();
                    }
                    releaseLastSocket(mSocket);
                    new InitSocketThread().start();
                }
            }
            mHandler.postDelayed(this, HEART_BEAT_RATE);
        }
    };

    /**
     * 断开重连
     */
    private Runnable reConnectRunnable = new Runnable() {

        @Override
        public void run() {
            mHandler.removeCallbacks(reConnectRunnable);
            if(null!=mReadThread){
                mReadThread.release();
            }
            releaseLastSocket(mSocket);
            new InitSocketThread().start();
        }
    };

    private boolean sendHeartBeat() {
        BaseRequestBean<String> bean=new BaseRequestBean<String>();
        //设置访问参数
        String json = GsonUtil.getGson().toJson(bean);
        return sendMsg(json);
    }

    private long sendTime = 0L;


    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        EventBus.getDefault().register(this);
        new InitSocketThread().start();
    }
    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";

                byte[] bytes = addTLV(os, msg.getBytes());

                os.write(bytes);
                os.flush();
                sendTime = System.currentTimeMillis();//每次发送成数据,就改一下最后成功发送的时间,节省心跳间隔时间
            } else {
                dealDisconnected();
                return false;
            }
        } catch (IOException e) {
            //错误,通道中断 ,没必要在发心跳包了
            mHandler.removeCallbacks(heartBeatRunnable);

            dealSocketConnectException(e,0);
            return false;
        }
        return true;
    }

    private void initSocket() {//初始化Socket
        try {
            Log.i(TAG, "---------------------initSocket--------------");
            Socket so = new Socket(Config.Host, Config.Post);
            mSocket = new WeakReference<Socket>(so);
            mReadThread = new ReadThread(so);
            mReadThread.start();

            //连接成功,不断发送心跳包
            mHandler.postDelayed(heartBeatRunnable, 0);

            //连接成功,移除重连任务
            mHandler.removeCallbacks(reConnectRunnable);
        } catch (UnknownHostException e) {
            dealSocketConnectException(e,RECONNECT_RATE);
        } catch (IOException e) {
            dealSocketConnectException(e,RECONNECT_RATE);
        }
    }

    private void releaseLastSocket(WeakReference<Socket> mSocket) {
        try {
            if (null != mSocket) {
                Socket sk = mSocket.get();
                if (null!=sk && !sk.isClosed()) {
                    sk.close();
                    Log.e(TAG, "-------------------Socket 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<Socket> mWeakSocket;
        private boolean isStart = true;
        public ReadThread(Socket socket) {
            mWeakSocket = new WeakReference<Socket>(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*3];
                    int length = 0;

                    byte [] data=null;
                    boolean isContinue=false;
                    int count=0;
                    int lengthData=0;
                    loop:   while (!socket.isClosed() && !socket.isInputShutdown()
                            && isStart && ((length = is.read(buffer)) != -1)) {

                        String message=null;

                        int tag = bytes2Int(buffer, 0);
                        //from包含 ,to  不包含
                        //to  由length计算  数据长度+tag
//                        new String(buffer,8,lengthData).trim();

                        //TLV数据,内容过长,则缓存起来,多次读取直到指定长度
                        if(tag==Constants.SOCKET_PROTO_TLV_TAG){
                            lengthData = bytes2Int(buffer, 4);
                            if(lengthData+8>length){
                                if(null==data  || data.length<lengthData){
                                    data=new byte[lengthData];
                                }
                                System.arraycopy(buffer ,8,data,0,length-8);
                                isContinue=true;
                                count=length-8;
                                continue ;
                            }else{
                                isContinue=false;
                                count=0;
                                message= new String(buffer,8,lengthData).trim();
                            }
                        }else if(isContinue){
                            if(count+length<lengthData){
                                System.arraycopy(buffer ,0,data,count,length);
                                isContinue=true;
                                count=count+length;
                                continue ;
                            }else {
                                System.arraycopy(buffer ,0,data,count,lengthData-count);
                                message= new String(data,0,lengthData).trim();
                                isContinue=false;
                                count=0;
                            }
                        }


                        sendTime = System.currentTimeMillis();//每次接收到数据,就改一下最后成功发送的时间,节省心跳间隔时间
                        if(null!=message){
                            Log.e(TAG, message);
                            dealResponseData(message);
                        }
                    }
                    length = is.read(buffer);
                    dealDisconnected();
                } catch (IOException e) {
                    dealSocketConnectException(e,0);
                }
            }
        }
    }

    //接收在其他页面发送的请求命令
    @Subscribe
    public void onEventMainThread(AnyEventType eventType) {
        switch (eventType.getCmd()) {
            case Constants.EVENT_SEND:
                String json = GsonUtil.getGson().toJson(eventType.getObj());
                sendMsg(json);
                break;
            default:
                break;
        }
    }

    @Override
    public boolean onUnbind(Intent intent) {
        EventBus.getDefault().unregister(this);
        Log.i(TAG, "---------------------onUnbind--------------");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "---------------------onDestroy--------------");
        mHandler.removeCallbacks(heartBeatRunnable);
        mHandler.removeCallbacks(reConnectRunnable);
        if(null!=mReadThread){
            mReadThread.release();
        }
        releaseLastSocket(mSocket);
        EventBus.getDefault().unregister(this);
    }


    private void dealSocketConnectException(Exception e,long delayMillis) {
        mHandler.postDelayed(reConnectRunnable, delayMillis);
        Log.e(TAG, "----------------------------"+e.getMessage());
    }

    /**
     * 处理socket中断问题
     */
    private void dealDisconnected() {
        //服务端中断,重连,  第一次马上重连,第二次则按间隔时间
        mHandler.postDelayed(reConnectRunnable, 0);
        //错误,通道中断 ,没必要在发心跳包了
        mHandler.removeCallbacks(heartBeatRunnable);
    }


    public  int bytes2Int(byte[] bytes,int pos){
        int num=bytes[pos] & 0xFF;
        num |=((bytes[pos+1] <<8)& 0xFF00);
        num |=((bytes[pos+2] <<16)& 0xFF0000);
        num |=((bytes[pos+3] <<24)& 0xFF000000);
        return num;
    }


    public byte[] int2ByteArray(int i){
        byte[] result=new byte[4];
        //大小端
      /*  result[0]=(byte)((i >> 24)& 0xFF);
        result[1]=(byte)((i >> 16)& 0xFF);
        result[2]=(byte)((i >> 8)& 0xFF);
        result[3]=(byte)(i & 0xFF);*/

        result[3]=(byte)((i >> 24)& 0xFF);
        result[2]=(byte)((i >> 16)& 0xFF);
        result[1]=(byte)((i >> 8)& 0xFF);
        result[0]=(byte)(i & 0xFF);
        return result;
    }

    /**
     * 对要发送的数据添加TLV
     * 变长头
     * @param os
     * @param message
     * @return
     * @throws IOException
     */
    private byte[] addTLV(OutputStream os, byte[] message) throws IOException {
        int pos=0;
        byte[] bytesTag = int2ByteArray(Constants.SOCKET_PROTO_TLV_TAG);
        byte[] bytesLength = int2ByteArray(message.length);
        int length=bytesLength.length+bytesTag.length+message.length;
        byte [] value = new byte[length];

        //将tag标识复制到目标数组
        System.arraycopy(bytesTag,0,value,0,bytesTag.length);
        pos=bytesTag.length;

        //将数据长度复制到目标数组
        System.arraycopy(bytesLength,0,value,pos,bytesLength.length);
        pos=pos+bytesLength.length;

        //将要发送的内容复制到数组
        System.arraycopy(message,0,value,pos,message.length);
        return value;
    }

    /**
     * 处理响应数据
     * @param message
     */
    private void dealResponseData(String message) {
        try {
            Type type = new TypeToken<BaseResponseBean>() {}.getType();
            BaseResponseBean bean = (BaseResponseBean) GsonUtil.getGson().fromJson(message, type);

            if(null!=bean && bean.getStatus()==Constants.ERR_CODE_OK){

                //收到服务器过来的消息,就通过Broadcast发送出去
                if(bean.getCmd()==Constants.CMD_HEARTBEAT){//处理心跳回复

                }else{
                    //其他消息回复
                                    /*int type = jsonObject.getInt("type");
                                    int seq = jsonObject.getInt("seq");
                                    if(cmd==Constants.CMD_CTRL_SCENE){
                                        Log.e("tag", message);
                                    }*/
                    JSONObject  jsonObject = new JSONObject(message);
                    String string=null;
                    boolean isBodyNull = jsonObject.isNull("body");
                    if(!isBodyNull){
                        string = jsonObject.getString("body");
                    }
                    //将响应结果发送出去
//                    EventBus.getDefault().post();
                }

            }else if(null!=bean){
                Log.e(TAG, bean.toString());
                mHandler.sendEmptyMessage(bean.getStatus());
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值