關於socket.getOutputStream() 的一些問題, OutputStream的flush是一個空方法,因此須要另外一個實現了Flush的流來包裝一下服務器
這裏爲何使用PrintWriter,而不使用BufferedWritersocket
緣由是在接收方使用BufferedReader 的readLine,而BufferedWriter.write並不會自動換行,因此會致使讀取阻塞,須要手動換行,代碼以下:測試
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); bw.write("你好啊"); // 由於在服務端使用的是readLine,因此若是不調用newLine,那麼會一直阻塞 bw.newLine(); bw.flush();
如下兩個測試類代碼,在輸出數據的時候,輸出空行爲結束符,在讀取輸入流的時候都在循環內判斷了readLine長度是否爲0(固然規範的作法是約定長度,根據長度判斷是否結束),緣由以下摘抄☞:點擊這裏spa
對於socket,不能認爲把某次寫入到流中的數據讀取完了就算流結尾了,可是socket流還存在,還能夠繼續往裏面寫入數據而後再讀取。因此用BufferedReader封裝socket的輸入流,調用BufferedReader的readLine方法是不會返回null的.net
因此在循環內若是不判斷 msg!=null&&msg.length()>0 那麼程序將會一直阻塞在這裏(程序是由於readLine阻塞,並非死循環)code
關於流的關閉會影響socket的使用,並且對一次鏈接關閉流之後,沒有辦法再次打開,哪怕只關閉輸入流,也會致使輸出流不能使用.反之亦然.server
因此若是在一次IO操做之後,還有另外一次IO,那麼就先不關閉.等所有用完再關閉.blog
ServerSocket get
@RunWith(JUnit4.class) public class ServerSocketTest { @Test public void testServer(){ ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(); // serverSocket.setReuseAddress(true); // System.out.println(InetAddress.getLocalHost());//獲取的本機地址不必定正確 serverSocket.bind(new InetSocketAddress(8000)); while(true){ //一旦鏈接,返回的socket包含客戶端信息的socket Socket socket = serverSocket.accept(); PrintWriter pw = new PrintWriter(socket.getOutputStream(),true); pw.println("host:"+socket.getInetAddress()+":"+socket.getPort()+"創建連接"); //這裏發送空行做爲結束符,固然規範作法是根據長度做爲標識 pw.println(""); //由於new PrinWriter的時候指定了autoFlush的參數爲true因此不用手動flush // pw.flush(); BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); for(String msg = br.readLine();msg!=null&&msg.length()>0;msg = br.readLine()){ System.out.println(msg); } pw.close(); br.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
ClientSocketit
/** * * @author lzw * */ @RunWith(JUnit4.class) public class SocketClient { @Test public void testClient() throws UnknownHostException, IOException{ //表示鏈接到服務器的 地址以及端口 SocketAddress address = new InetSocketAddress("19.95.103.112",8000); Socket socket = new Socket(); socket.connect(address,60000);//鏈接 //讀取服務端返回的數據 getMsb(socket); sendMsg(socket); socket.close(); } private void sendMsg(Socket socket){ PrintWriter pw = null; // BufferedWriter bw = null; try { // bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); // bw.write("你好啊"); //由於在服務端使用的是readLine,因此若是不調用newLine,那麼會一直阻塞 // bw.newLine(); // bw.flush(); // OutputStream os = socket.getOutputStream(); // //這個是一個空方法 // os.flush(); pw = new PrintWriter(socket.getOutputStream(),true); pw.println("你好啊");
//輸出空行做爲結束標識
pw.println(""); //由於new PrinWriter的時候指定了autoFlush的參數爲true因此不用手動flush // pw.flush(); } catch (IOException e) { e.printStackTrace(); }finally{ //由於本次鏈接,到這個方法之後沒有更多交互,因此能夠關閉 if(pw!=null){ pw.close(); } } } private void getMsb(Socket socket){ InputStream is = null; BufferedReader br = null; try { is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); for(String msg = br.readLine();msg!=null&&msg.length()>0;msg = br.readLine()){ System.out.println(msg+"--"); } } catch (IOException e) { e.printStackTrace(); }finally{ //這裏不能關閉流,不然會把socket也關閉了(由於後面還要發送數據,因此不能關閉流,無論是關閉輸入輸入其中之一,都會致使輸入和輸出都不能使用) // try { // if(br!=null) // br.close(); // } catch (IOException e) { // e.printStackTrace(); // } } } }