聲明:該博文以socket中,關閉輸出流為例進行說明。
為了方便講解,我們把DataOutputstream dout = new DataOutputStream(new BufferedOutputStream(mySocket.getOutputStream()));中的dout做為Socket輸出流的代言。同樣的,din是輸入流的代言。
可以造成dout被關閉的操作有:
1、調用dout.close();或din.close();因為使用這種流關閉,會造成socket被關閉,所以輸入輸出流都將不可再用。
2、調用socket.close();
3、調用socket.shutdownOutputStream();單方面關閉dout,此時din還可正常使用。
以下,我將對socket中關閉輸出流進行3個測試
輸出流關閉測試一:socket關閉嗎?
輸出流關閉測試二:該流是否可以重新開啟?
輸出流關閉測試三:輸出緩沖區里的數據是丟棄,還是發送?
測試結果如下:
測試一:dout.close();會造成socket被關閉,但socket.shutdownOutputStream()不會。
測試二:不可以,會拋出異常!
測試三:丟棄
客戶端程序:
package com.test2; import java.io.*; import java.net.*; /** * @ClassName: SocketTest * @Description: 測試Socket中,流關閉后,socket是否關閉?是否可重開流?輸出緩存區的數據是發送出去,還是丟棄? * @author 慢跑學Android * @date 2011-11-12 上午11:15:21 * */ public class SocketTest { Socket mySocket; DataOutputStream dout; public static void main(String[] args){ new SocketTest(); } public SocketTest(){ // 輸出流關閉的測試一:socket關閉嗎? test1(); // 輸出流關閉測試二:該流是否可以重新開啟? test2(); // 輸出流關閉測試三:輸出緩沖區里的數據是丟棄,還是發送? test3(); } private void test1() { // 輸出流關閉的測試一:socket關閉嗎? System.out.println("\n****2種方式關閉輸出流,Socket是否關閉?***\n"); try { mySocket = new Socket("27.154.122.233",9999); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { dout = new DataOutputStream(new BufferedOutputStream(mySocket.getOutputStream())); //下面這一句主要是用來證明socket確實處於開啟狀態 System.out.println("輸出流剛打開,Socket是否關閉?" + mySocket.isClosed()); mySocket.shutdownOutput(); System.out.println("使用shutdownOutput關閉輸出流,Socket是否關閉?" + mySocket.isClosed()); dout.close(); System.out.println("使用close關閉輸出流,Socket是否關閉?" + mySocket.isClosed()); } catch (IOException e) { e.printStackTrace(); } } private void test2() { // 輸出流關閉測試二:使用shutdownOutputStream后,輸出流是否可以重新開啟? System.out.println("\n****使用shutdownOutputStream后,輸出流是否可以重新開啟?***\n"); try { mySocket = new Socket("27.154.122.233",9999); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { dout = new DataOutputStream(new BufferedOutputStream(mySocket.getOutputStream())); mySocket.shutdownOutput(); // 重開輸出流 dout = new DataOutputStream(mySocket.getOutputStream()); dout.writeUTF("是否允許我重開?"); // 清空輸出緩存,確保當dout通道沒問題時,消息可以到達服務器 dout.flush(); } catch (IOException e) { e.printStackTrace(); } finally { try { mySocket.close(); } catch (IOException e) { e.printStackTrace(); } } } private void test3(){ // 輸出流關閉測試三:輸出緩沖區里的數據是丟棄,還是發送? System.out.println("\n***輸出緩沖區里的數據是丟棄,還是發送?****\n"); try { mySocket = new Socket("27.154.122.233",9999); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { dout = new DataOutputStream(new BufferedOutputStream(mySocket.getOutputStream())); dout.writeUTF("shutdownOutput后,數據發得得出去嗎?"); mySocket.shutdownOutput(); } catch (IOException e) { e.printStackTrace(); } } }
服務器端程序:
/** * @Title: ServerSocketTest.java * @Package com.test1 * @Description: TODO(該文件為”Socket中,流關閉后,發生什么事“的Sever測試端) * @author 慢跑學Android * @date 2011-11-12 上午11:31:05 * @version V1.0 */ package com.test1; import java.io.*; import java.net.*; public class ServerSocketTest extends Thread{ private ServerSocket myServerSocket; private final int PORT = 9999; public static void main(String[] args){ ServerSocketTest sst = new ServerSocketTest(); sst.start(); } public ServerSocketTest(){ // 初始化一個ServeSocket端 try { myServerSocket = new ServerSocket(PORT); } catch (IOException e) { e.printStackTrace(); } } public void run(){ while(true){ System.out.println("我是服務器,我在9999端口監聽...."); try { Socket socket = myServerSocket.accept(); DataInputStream din = new DataInputStream(new BufferedInputStream(socket.getInputStream())); String msgIn = din.readUTF(); System.out.println(msgIn.trim()); } catch (IOException e) { e.printStackTrace(); } } } }
說明一點:
在test3()中,因為dout = new DataOutputStream(newBufferedOutputStream(mySocket.getOutputStream()));使用了Buffered,所以在dout.writeUTF()方法后,如果沒有使用dout.flush();數據會存在輸出緩存中,不會發送出去的。
如果我們隊dout的聲明是,dout = new DataOutputStream(mySocket.getOutputStream());那么,數據會立即發送出去。(除非,對方沒有調用read()來讀取數據,且數據量極大,超過了對方的輸入緩存。不過,此時dout.writeUTF();這里會堵塞。)
以下是程序運行后,客戶端與服務器各自的控制台輸出情況:
----------------------------------客戶端--------------------------
java.net.SocketException: Socket output is shutdown
at java.net.Socket.getOutputStream(Unknown Source)
at com.test2.SocketTest.test2(SocketTest.java:66)
at com.test2.SocketTest.<init>(SocketTest.java:22)
at com.test2.SocketTest.main(SocketTest.java:15)
****2種方式關閉輸出流,Socket是否關閉?***
輸出流剛打開,Socket是否關閉?false
使用shutdownOutput關閉輸出流,Socket是否關閉?false
使用close關閉輸出流,Socket是否關閉?true
****使用shutdownOutputStream后,輸出流是否可以重新開啟?***
***輸出緩沖區里的數據是丟棄,還是發送?****
---------------------------------服務器------------------------------
我是服務器,我在9999端口監聽....
我是服務器,我在9999端口監聽....
java.io.EOFException
at java.io.DataInputStream.readUnsignedShort(Unknown Source)
at java.io.DataInputStream.readUTF(Unknown Source)
at java.io.DataInputStream.readUTF(Unknown Source)
at com.test1.ServerSocketTest.run(ServerSocketTest.java:37)
java.io.EOFException
at java.io.DataInputStream.readUnsignedShort(Unknown Source)
at java.io.DataInputStream.readUTF(Unknown Source)
at java.io.DataInputStream.readUTF(Unknown Source)
at com.test1.ServerSocketTest.run(ServerSocketTest.java:37)
java.io.EOFException
at java.io.DataInputStream.readUnsignedShort(Unknown Source)
我是服務器,我在9999端口監聽....
at java.io.DataInputStream.readUTF(Unknown Source)
at java.io.DataInputStream.readUTF(Unknown Source)
at com.test1.ServerSocketTest.run(ServerSocketTest.java:37)
Reference:
Java socket中關閉IO流后,發生什么事?(以關閉輸出流為例)
