现在一款成熟的app一般都会具备长连接推送功能,那么我们要想项目具备长连接的功能现在又两种选择的方案,一种基于原生tcp协议的socket长连接,另外一种基于ws协议的websocket的长连接,今天我们演示两种socket长连接的实现集成方式(1、基于Oksocet框架实现socket长连接   2、基于OKhttp的实现的websocket的链接)下面分别是引用的连接

implementation 'com.squareup.okhttp3:okhttp:3.10.0'  (websocket实现)
implementation 'com.tonystark.android:socket:3.1.0'   (socket实现)

我是基于我现在公司的长连接来做得测试,我们公司为了兼容客户端和小程序,针对socket和websocket都做了兼容,做了两种方案,我就以这两种方案来讲解下我的实现历程

1.这是websocket连接的监听累,针对连接成功,连接失败和数据接收的回调

public class EchoWebSocketListener extends WebSocketListener {

    Gson gson = new Gson();
    private disConnectListener listener;

    public EchoWebSocketListener(disConnectListener listener) {
        this.listener = listener;
    }

    @Override
    public void onOpen(WebSocket webSocket, Response response) {

    }

    @Override
    public void onMessage(WebSocket webSocket, String text) {

        AuthBean authBean = gson.fromJson(text, AuthBean.class);
        if (TextUtils.equals(authBean.getCmd(), "auth1")) { //发送认证消息
            String encode = MD5Utils.encode(authBean.getResult().getSeed() + "6PIRqVw3cRm84dKVg"); //由于是公司在线业务,所以加密串不能展示,原理是做MD5秘钥签名
            String s = sendData(encode);
            webSocket.send(s);
        }


        output("onMessage: " + text);
    }

    @Override
    public void onMessage(WebSocket webSocket, ByteString bytes) {
        output("onMessage byteString: " + bytes);
    }

    @Override
    public void onClosing(WebSocket webSocket, int code, String reason) {
        webSocket.close(1000, null);
        output("onClosing: " + code + "/" + reason);
    }

    @Override
    public void onClosed(WebSocket webSocket, int code, String reason) {
        output("onClosed: " + code + "/" + reason);
    }

    @Override

    public void onFailure(WebSocket webSocket, Throwable t, Response response) {
        output("onFailure: " + t.getMessage());
        listener.reconnect();
    }

    private void output(String params) {
        System.out.println(params);
    }

    private String sendData(String sign) {
        String jsonHead = "";
        Map<String, Object> mapHead = new HashMap<>();
        mapHead.put("cmd", "auth2");
        mapHead.put("msg_id", "1");
        mapHead.put("authCode", sign);
        mapHead.put("userId", "111");
        jsonHead = buildRequestParams(mapHead);
        Log.e("TAG", "sendData: " + jsonHead);
        return jsonHead;
    }

    public static String buildRequestParams(Object params) {
        Gson gson = new Gson();
        String jsonStr = gson.toJson(params);
        return jsonStr;
    }

    //定义失败回调的接口
    interface disConnectListener {
        void reconnect();
    }

}

2、这是连接的类的具体的实现,通过handler实现心跳的发送,在创建监听类的时候,实现失败重连机制,界面销毁的时候,断开连接

public class OkhttpActivity extends AppCompatActivity {

    private OkHttpClient client;
    private long sendTime = 0L;
    // 发送心跳包
    private Handler mHandler = new Handler();
    // 每隔2秒发送一次心跳包,检测连接没有断开
    private static final long HEART_BEAT_RATE = 2 * 1000;

    // 发送心跳包
    private Runnable heartBeatRunnable = new Runnable() {
        @Override
        public void run() {
            if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) {
                String message = sendData();
                mSocket.send(message);
                sendTime = System.currentTimeMillis();
            }
            if (mHandler != null) {
                mHandler.postDelayed(this, HEART_BEAT_RATE); //每隔一定的时间,对长连接进行一次心跳检测
            }
        }
    };
    private WebSocket mSocket;
    private Request request;
    private EchoWebSocketListener listener;


    private String sendData() {
        String jsonHead = "";
        Map<String, Object> mapHead = new HashMap<>();
        mapHead.put("cmd", "wd_heartbeat");

        jsonHead = buildRequestParams(mapHead);
        Log.e("TAG", "sendData: " + jsonHead);
        return jsonHead;
    }

    public static String buildRequestParams(Object params) {
        Gson gson = new Gson();
        String jsonStr = gson.toJson(params);
        return jsonStr;
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_okhttp);
        listener = new EchoWebSocketListener(new EchoWebSocketListener.disConnectListener() {
            @Override
            public void reconnect() {
                if(mHandler!=null){
                    mSocket = client.newWebSocket(request, listener);
                }
            }
        });
//        Request request = new Request.Builder().url("ws://echo.websocket.org").build();
        request = new Request.Builder().url("wss://xxxxxx/ws").build();
        client = new OkHttpClient();
        mSocket = client.newWebSocket(request, listener);
        mHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
        mHandler = null;
        mSocket.cancel();
        mSocket.close(1000,null);
    }
}

日志输出:(服务端做了auth的认证,首次连接成功要认证,认证通过才能发送消息)

android的长连接 app长连接_长连接

 

/*******************Socket实现socket长连接的实现**************************************/

 

按照下面代码创建socket长连接,界面销毁的时候断开连接(注意的时候:在接收到心跳包的时候,要通过判断是否是接收的心跳包的回调,对接收的数据进行框架的喂狗操作,如果没有这一步操作的话,监控狗会自动断开连接//进行心跳包的喂狗操作 if (TextUtils.equals(authBean.getCmd(), "wd_heartbeat")) { manager.getPulseManager().feed(); })

//连接参数设置(IP,端口号),这也是一个连接的唯一标识,不同连接,该参数中的两个值至少有其一不一样
        ConnectionInfo info = new ConnectionInfo(
                "jdsim.jindashi.cn", 9527);
//调用OkSocket,开启这次连接的通道,拿到通道Manager
        manager = OkSocket.open(info);
//注册Socket行为监听器,SocketActionAdapter是回调的Simple类,其他回调方法请参阅类文档
        manager.registerReceiver(new SocketActionAdapter() {
            @Override
            public void onSocketConnectionSuccess(Context context, ConnectionInfo info, String action) {
                Toast.makeText(context, "连接成功", Toast.LENGTH_SHORT).show();
                manager.getPulseManager().setPulseSendable(new TestSendData()).pulse();//发送心跳
            }

            @Override
            public void onSocketReadResponse(Context context, ConnectionInfo info, String action, OriginalData data) {
                byte[] bodyBytes = data.getBodyBytes();
                try {
                    String s = new String(bodyBytes, "UTF-8");
//                    System.out.println((String)bodyBytes);
                    AuthBean authBean = gson.fromJson(s, AuthBean.class);
                    if (TextUtils.equals(authBean.getCmd(), "auth1")) {
                        manager.send(new SendAuthData(authBean.getResult().getSeed()));
//                        manager.getPulseManager().setPulseSendable(new TestSendData()).pulse();//发送心跳
                    }
                    //进行心跳包的喂狗操作
                    if (TextUtils.equals(authBean.getCmd(), "wd_heartbeat")) {
                        manager.getPulseManager().feed();
                    }
                    System.out.println("响应输出" + s);
                } catch (UnsupportedEncodingException e) {
                    System.out.println("数据异常NG>>>>>>>>");
                    e.printStackTrace();
                }
            }

        });
//调用通道进行连接
        manager.connect();

日志输出:

android的长连接 app长连接_长连接的实现方案_02