使用socket讀取服務器發送的數據問題

剛剛項目使用到socket進行數據的傳送,其中數據的讀取問題着實
費了老大的勁,以此分享希望能讓有緣人少走彎路。

new Thread() {
            @Override
            public void run() {
                try {
                    mSocket = new Socket(SERVICEADD, DST_PORT);
                    //設置socket讀取數據流的超時時間
                    mSocket.setSoTimeout(5000);
                    mSocket.setTcpNoDelay(true);
                    //設置客戶端close()方法起作用時延時30s關閉socket
                    mSocket.setSoLinger(true, 30);
                    mSocket.setSendBufferSize(4096);
                    //防止服務器端無效時,客戶端長時間處於連接狀態
                    mSocket.setKeepAlive(true);
                    OutputStream ou = mSocket.getOutputStream();
                    //向服務器發送要查詢的數據
                    ou.write(queryContent.getBytes());
                    ou.flush();
                    //讀取發來服務器信息
                    BufferedReader br = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
                    List<QueryDatas> queryDatases = QueryFomart.formatSocketString(br);
                    EventBus.getDefault().post(queryDatases);
                    br.close();
                    mSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();

對於使用readLine讀取數據的一個問題就是,無法走到while後面去,究其原因:

1.誤以爲readLine()是讀取到沒有數據時就返回null(因爲其它read方法當讀到沒有數據時返回-1),而實際上readLine()是一個阻塞函數,當沒有數據讀取時,就一直會阻塞在那,而不是返回null;因爲readLine()阻塞後,System.out.println(message)這句根本就不會執行到,所以在接收端就不會有東西輸出。要想執行到System.out.println(message),一個辦法是發送完數據後就關掉流,這樣readLine()結束阻塞狀態,而能夠得到正確的結果,但顯然不能傳一行就關一次數據流;另外一個辦法是把System.out.println(message)放到while循環體內就可以。

2.readLine()只有在數據流發生異常或者另一端被close()掉時,纔會返回null值。

3.如果不指定buffer大小,則readLine()使用的buffer有8192個字符。在達到buffer大小之前,只有遇到”/r”、”/n”、”/r/n”纔會返回。

小結,使用readLine()一定要注意:

1、讀入的數據要注意有/r或/n或/r/n
2、沒有數據時會阻塞,在數據流異常或斷開時纔會返回null
3、使用socket之類的數據流時,要避免使用readLine(),以免爲了等待一個換行/回車符而一直阻塞
4、或者是服務器端在發送完數據就進行關閉

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