Socket請求中readLine()方法引發的思考
背景:
今天沒事自己模擬socket請求時發現了一個問題:
//測試程式碼 public static void http(String path) throws Exception { URL url = new URL(path); final String host = url.getHost(); //如果指明瞭埠,則拿到埠,否則是-1 int port = url.getPort(); int defaultPort = url.getDefaultPort(); final String file = url.getFile(); Socket socket = new Socket(host, port == -1 ? defaultPort : port); InputStream is = socket.getInputStream(); final BufferedReader br = new BufferedReader(new InputStreamReader(is)); final OutputStream os = socket.getOutputStream(); //開啟一個執行緒用來讀取資料 new Thread(){ @Override public void run() { String line; try { while ((line = br.readLine()) != null){ Log.e("TAG",line); } } catch (IOException e) { e.printStackTrace(); } } }.start(); //開啟一個執行緒用來發送資料 new Thread(){ @Override public void run() { SystemClock.sleep(10000); try { //請求行 os.write(("GET "+file+" HTTP/1.1\r\n").getBytes()); os.write(("Host: "+host+"\r\n").getBytes()); os.write(("\r\n").getBytes()); os.flush(); }catch (Exception e){} } }.start(); /*//請求行 os.write(("GET "+file+" HTTP/1.1\r\n").getBytes()); os.write(("Host: "+host+"\r\n").getBytes()); os.write(("\r\n").getBytes()); os.flush();*/ }
通過程式碼都能看到:
我用了兩種測試方式:
第一次:開啟一個執行緒用來讀取資料,傳送資料沒有在子執行緒中傳送,但是是在讀取資料方法的下面。按照常理來說這樣的程式碼會先執行讀取資料的方法。結果通過斷點除錯發現是先執行的傳送資料的方法,然後執行的讀取資料的方法。這裡可能就會有人說了開啟執行緒需要少量的時間。好,那麼我就有了第二次測試。
第二次(如上面程式碼):我把傳送資料的程式碼也在z執行緒中執行,並且在該執行緒中睡10秒之後在執行傳送資料的程式碼,結果還是和上面一樣:先執行的傳送資料的程式碼,然後再執行的讀資料的方法。
針對上面問題其實有一個誤解,就是對readLine()方法的誤解。 誤以為readLine()是讀取到沒有資料時就返回null。而實際上readLine()是一個阻塞函式。當沒有資料讀取時,就會造成IO阻塞,這個方法就會一直阻塞在這裡。所以只有等傳送資料的方法執行完之後,readLine()才會讀取到資料,接著下面的才會正常執行。