Java socket中關閉IO流后,發生什么事?(以關閉輸出流為例)


聲明:該博文以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流后,發生什么事?(以關閉輸出流為例)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM