剛剛項目使用到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、或者是服務器端在發送完數據就進行關閉