比心跳包更優質的網絡監聽解決方案

一,提到客戶端需要監聽與服務器的連接是否斷開首當其衝想到的時用心跳包解決,最近plc中控系統時最開始我也是通過發送緊急請求數據來達到心跳檢查的效果,以往服務器對緊急狀態碼是默認不處理的,但是PLC確響應了該數據,由於plc沒玩多久不好處理,故在前端進行改良。

二,改良方案:isusnpStream.read()是阻塞式方法,當socket的通信斷開時此刻值爲-1,那麼就可以用-1來判斷當前socket是否斷開連接:方法如下貼上inputStream線程方法。

Thread threadIn = new Thread(new Runnable() {
    @Override
    public void run() {
        while (isClient) {
            Log.e("當前線程In:", Thread.currentThread() + "");
            try {
                int i = 0;
                in = client.getInputStream();
                byte[] bt = new byte[1024];
                while ((i = in.read(bt)) != -1) {
                    //input.read爲阻塞io,讀完當前數據會進入阻塞狀態等待下一條數據,當斷開時值爲-1,跳出當前循環
                    str = new String(bt, 0, i);
                }
                //當in.read值爲-1時,則視爲與主機斷開,此時關閉scoket以及輸入輸出流重新請求主機,並且跳出while循環
                netUtilScoket.safeClose(client);
                netUtilScoket.safeClose(in);
                netUtilScoket.safeClose(out);
                isClient = false;
            } catch (IOException e) {
                Log.e("socket連接斷開", " Socket is closed" + e);
            }
        }
        openClientThread();//連接服務器scoket方法
    }l
});

這一步可以判斷在通信過程中網絡斷開連接,下一步要解決的問題就是重連時如何判斷是否重連成功,也包括初始化連接時是否連接成功的判斷,在這裏有一點大家需要注意很多兄弟都會以爲socket.setSotimeout(5000)方法時用來設置socket的連接超時的,事實上這並不是而是數據接受的超時時間設置,所以不要用該方法的時間來判斷是否連接成功,socket=new socket(ip,port);會強制加上try cath 方法,當出現異常時則視爲沒有連接成功,此刻可以嘗試進行第二次socket連接,這樣和心跳包定時連接服務器的好處在哪裏呢?如果心跳包時間間隔太多,會導致前面幾次連接並沒失敗的情況下你進行了成功的連接,這樣一次性會給socketServe端瞬間增加好幾個連接對象。下面貼下連接代碼:

 /**
     * @effect 開啓線程建立連接開啓客戶端
     */
    public void openClientThread() {
        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    /**
                     *  connect()步驟
                     * */
                    client = new Socket(site, port);
                    client.setSoTimeout(0);
                    if (client != null) {
                     //連接成功
                        isClient = true;
                        forOut();//初始化輸出流
                        forIn();//開啓輸入流線程
                    } else {
                        isClient = false;
                        Looper.prepare();
                        Toast.makeText(context, "網絡連接失敗", Toast.LENGTH_LONG).show();
                        Looper.loop();
                    }
                } catch (UnknownHostException e) {
                    e.printStackTrace()
                } catch (IOException e) {
                    netUtilScoket.safeClose(client);
                    netUtilScoket.safeClose(in);
                    netUtilScoket.safeClose(out);
                    e.printStackTrace();
                    //連接時失敗,重新連接
                    openClientThread();
                }

            }
        });
       //線程池控制
        defaultThreadPool().execute(thread);
    }

三,當然各種監聽方法各有取捨,這裏只是提供一個實現思路,希望能大家提供一點幫助。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章