Socket连接与断开重连

                                      Socket连接与断开重连

 

       近期在做一个与硬件交互的项目,通过TCP/IP协议通讯。

       首先来看一下Socket通信模型

       思路是使用service,需要频繁的与服务端交互所以使用BindService

创建绑定服务

必须使用IBinder,用以提供客户端与服务交互的接口

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return socketBinder;
    }

    public class SocketBinder extends Binder {
        public SocketService getService() {
            return SocketService.this;
        }
    }

初始化socket,使用EventBus发送连接状态

/**
 * 初始化socket
 */
private void initSocket() {
    if (socket == null && connectThread == null) {
        connectThread = new Thread(new Runnable() {
            @Override
            public void run() {
                socket = new Socket();
                try {
                    socket.connect(new InetSocketAddress(Parameter.SERVER_IP, Parameter.PORT), 2000);//超时时间为2秒
                    if (socket.isConnected()) {//发送心跳包
                        toastMsg("socket已连接");
                        EventMsg msg = new EventMsg();
                        msg.setTag("success");
                        EventBus.getDefault().post(msg);
                        sendBeatData();//发送心跳数据
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    if (e instanceof SocketTimeoutException) {
                        toastMsg("连接超时,正在重连");
                        releaseSocket();
                    } else if (e instanceof NoRouteToHostException) {
                        toastMsg("该地址不存在,请检查");
                        stopSelf();
                    } else if (e instanceof ConnectException) {
                        toastMsg("连接异常或被拒绝,请检查");
                        stopSelf();
                    }
                }
            }
        });
        connectThread.start();
    }
}

使用TimerTask发送心跳数据,如果断开连接则重连

/**
 * 定时发送数据
 */
private void sendBeatData() {
    if (timer == null) {
        timer = new Timer();
    }

    if (task == null) {
        task = new TimerTask() {
            @Override
            public void run() {
                try {
                    outputStream = socket.getOutputStream();
                    byte[] b = {1};
                    outputStream.write(b);
                    outputStream.flush();
                } catch (Exception e) {
//                        toastMsg("连接断开,正在重连");
                    releaseSocket();//重连
                    e.printStackTrace();
                }
            }
        };
    }
    timer.schedule(task, 0, 5000);
}

判断是否需要重连,如果应用在后台把是否重连置为false

ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List appProcesses = activityManager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
    if (appProcess.processName.equals(getPackageName())) {
        if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
            Log.i(TAG, "后台 " + appProcess.processName);
            isReConnect = false;
        } else {
            Log.i(TAG, "前台 " + appProcess.processName);
            isReConnect = true;
        }
    }
}

解绑服务释放资源

/**
 * 释放资源
 */
private void releaseSocket() {
    if (task != null) {
        task.cancel();
        task = null;
    }
    if (timer != null) {
        timer.purge();
        timer.cancel();
        timer = null;
    }
    if (outputStream != null) {
        try {
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        outputStream = null;
    }
    if (socket != null) {
        try {
            socket.close();
        } catch (IOException e) {
            Log.e(TAG, "IOException: " + e.toString());
        }
        socket = null;
    }
    if (connectThread != null) {
        connectThread = null;
    }

    //...
}

向服务端发送数据

/**
 * 发送数据
 */
public void sendOrder(final byte[] b) {
    if (socket != null && socket.isConnected()) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    outputStream = socket.getOutputStream();
                    if (outputStream != null) {
                        outputStream.write(b);
                        outputStream.flush();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    } else {
        toastMsg("socket连接错误,请重试");
    }
}

 

Activity调用服务

调用bindService(),传递ServiceConnection

private ServiceConnection mServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        SocketService.SocketBinder binder = (SocketService.SocketBinder) iBinder;
        mSocketService = binder.getService();
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {

    }
};


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

    Intent intent = new Intent(this, SocketService.class);
    bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
}

应用退出时解绑服务调用unBindService()

@Override
protected void onDestroy() {
    super.onDestroy();

    unbindService(mServiceConnection);
}

应用从后台回到前台需要把重连置为true,重新初始化socket连接

@Override
protected void onStart() {
    super.onStart();
    if (null != mSocketService)
        mSocketService.setIsReConnect(true);
}

 

完整service

package com.aole.PEConsole.service;

import android.app.ActivityManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;

import com.aole.PEConsole.event.EventMsg;
import com.aole.PEConsole.wiget.Parameter;

import org.greenrobot.eventbus.EventBus;

import java.io.IOException;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.NoRouteToHostException;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/**
 * author    valiant
 * date      2019/5/20.
 * describe  socket服务
 */
public class SocketService extends Service {

    private static final String TAG = "SocketService1";
    private Socket socket;
    private Thread connectThread;
    private Timer timer = new Timer();
    private OutputStream outputStream;
    private SocketBinder socketBinder = new SocketBinder();
    private TimerTask task;
    private boolean isReConnect = true;//默认重连

    private Handler handler = new Handler();

    public SocketService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        initSocket();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return socketBinder;
    }

    public class SocketBinder extends Binder {
        public SocketService getService() {
            return SocketService.this;
        }
    }

    /**
     * 初始化socket
     */
    private void initSocket() {
        if (socket == null && connectThread == null) {
            connectThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    socket = new Socket();
                    try {
                        socket.connect(new InetSocketAddress(Parameter.SERVER_IP, Parameter.PORT), 2000);//超时时间为2秒
                        if (socket.isConnected()) {//发送心跳包
                            toastMsg("socket已连接");
                            EventMsg msg = new EventMsg();
                            msg.setTag("success");
                            EventBus.getDefault().post(msg);
                            sendBeatData();//发送心跳数据
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        if (e instanceof SocketTimeoutException) {
                            toastMsg("连接超时,正在重连");
                            releaseSocket();
                        } else if (e instanceof NoRouteToHostException) {
                            toastMsg("该地址不存在,请检查");
                            stopSelf();
                        } else if (e instanceof ConnectException) {
                            toastMsg("连接异常或被拒绝,请检查");
                            stopSelf();
                        }
                    }
                }
            });
            connectThread.start();
        }
    }

    private void toastMsg(final String msg) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
            }
        });
    }

    public void setIsReConnect(boolean isReConnect) {
        this.isReConnect = isReConnect;
        if (isReConnect && null == socket) {
            initSocket();
        }
    }

    /**
     * 发送数据
     */
    public void sendOrder(final byte[] b) {
        if (socket != null && socket.isConnected()) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        outputStream = socket.getOutputStream();
                        if (outputStream != null) {
                            outputStream.write(b);
                            outputStream.flush();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        } else {
            toastMsg("socket连接错误,请重试");
        }
    }


    /**
     * 定时发送数据
     */
    private void sendBeatData() {
        if (timer == null) {
            timer = new Timer();
        }

        if (task == null) {
            task = new TimerTask() {
                @Override
                public void run() {
                    try {
                        outputStream = socket.getOutputStream();
                        byte[] b = {1};
                        outputStream.write(b);
                        outputStream.flush();
                    } catch (Exception e) {
//                        toastMsg("连接断开,正在重连");
                        releaseSocket();//重连
                        e.printStackTrace();
                    }
                }
            };
        }
        timer.schedule(task, 0, 5000);
    }

    /**
     * 释放资源
     */
    private void releaseSocket() {
        if (task != null) {
            task.cancel();
            task = null;
        }
        if (timer != null) {
            timer.purge();
            timer.cancel();
            timer = null;
        }
        if (outputStream != null) {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            outputStream = null;
        }
        if (socket != null) {
            try {
                socket.close();
            } catch (IOException e) {
                Log.e(TAG, "IOException: " + e.toString());
            }
            socket = null;
        }
        if (connectThread != null) {
            connectThread = null;
        }

        ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        List appProcesses = activityManager.getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            if (appProcess.processName.equals(getPackageName())) {
                if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
                    Log.i(TAG, "后台 " + appProcess.processName);
                    isReConnect = false;
                } else {
                    Log.i(TAG, "前台 " + appProcess.processName);
                    isReConnect = true;
                }
            }
        }

        //重新初始化socket
        if (isReConnect) {
            toastMsg("连接断开,正在重连");
            initSocket();
        }
    }
}

 

不要忘记在manifest文件中注册service



    
        
    

    

亲测有效,有什么不妥之处请指出。非常感谢

 

你可能感兴趣的:(原创,socket通讯)