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()不会。

测试二:不可以,会抛出异常!

测试三:丢弃

微笑客户端程序:

[java]  view plain  copy
  1. package com.test2;  
  2. import java.io.*;  
  3. import java.net.*;  
  4. /** 
  5. * @ClassName: SocketTest 
  6. * @Description: 测试Socket中,流关闭后,socket是否关闭?是否可重开流?输出缓存区的数据是发送出去,还是丢弃? 
  7. * @author 慢跑学Android 
  8. * @date 2011-11-12 上午11:15:21 
  9.  
  10. */  
  11. public class SocketTest {  
  12.     Socket mySocket;  
  13.     DataOutputStream dout;  
  14.     public static void main(String[] args){  
  15.         new SocketTest();  
  16.     }  
  17.       
  18.     public SocketTest(){  
  19.         // 输出流关闭的测试一:socket关闭吗?  
  20.         test1();  
  21.         // 输出流关闭测试二:该流是否可以重新开启?  
  22.         test2();  
  23.         // 输出流关闭测试三:输出缓冲区里的数据是丢弃,还是发送?  
  24.         test3();  
  25.     }  
  26.   
  27.     private void test1() {  
  28.         // 输出流关闭的测试一:socket关闭吗?  
  29.         System.out.println("\n****2种方式关闭输出流,Socket是否关闭?***\n");  
  30.         try {  
  31.             mySocket = new Socket("27.154.122.233",9999);  
  32.         } catch (UnknownHostException e) {  
  33.             e.printStackTrace();  
  34.         } catch (IOException e) {  
  35.             e.printStackTrace();  
  36.         }  
  37.           
  38.         try {  
  39.             dout = new DataOutputStream(new BufferedOutputStream(mySocket.getOutputStream()));  
  40.             //下面这一句主要是用来证明socket确实处于开启状态  
  41.             System.out.println("输出流刚打开,Socket是否关闭?" + mySocket.isClosed());  
  42.             mySocket.shutdownOutput();  
  43.             System.out.println("使用shutdownOutput关闭输出流,Socket是否关闭?" + mySocket.isClosed());  
  44.             dout.close();  
  45.             System.out.println("使用close关闭输出流,Socket是否关闭?" + mySocket.isClosed());  
  46.         } catch (IOException e) {  
  47.             e.printStackTrace();  
  48.         }  
  49.     }  
  50.   
  51.     private void test2() {  
  52.         // 输出流关闭测试二:使用shutdownOutputStream后,输出流是否可以重新开启?  
  53.         System.out.println("\n****使用shutdownOutputStream后,输出流是否可以重新开启?***\n");  
  54.         try {  
  55.             mySocket = new Socket("27.154.122.233",9999);  
  56.         } catch (UnknownHostException e) {  
  57.             e.printStackTrace();  
  58.         } catch (IOException e) {  
  59.             e.printStackTrace();  
  60.         }  
  61.           
  62.         try {  
  63.             dout = new DataOutputStream(new BufferedOutputStream(mySocket.getOutputStream()));  
  64.             mySocket.shutdownOutput();  
  65.             // 重开输出流  
  66.             dout = new DataOutputStream(mySocket.getOutputStream());  
  67.             dout.writeUTF("是否允许我重开?");  
  68.             // 清空输出缓存,确保当dout通道没问题时,消息可以到达服务器  
  69.             dout.flush();  
  70.         } catch (IOException e) {  
  71.             e.printStackTrace();  
  72.         } finally {  
  73.             try {  
  74.                 mySocket.close();  
  75.             } catch (IOException e) {  
  76.                 e.printStackTrace();  
  77.             }  
  78.         }  
  79.     }  
  80.       
  81.     private void test3(){  
  82.         // 输出流关闭测试三:输出缓冲区里的数据是丢弃,还是发送?  
  83.         System.out.println("\n***输出缓冲区里的数据是丢弃,还是发送?****\n");  
  84.         try {  
  85.             mySocket = new Socket("27.154.122.233",9999);  
  86.         } catch (UnknownHostException e) {  
  87.             e.printStackTrace();  
  88.         } catch (IOException e) {  
  89.             e.printStackTrace();  
  90.         }  
  91.           
  92.         try {  
  93.             dout = new DataOutputStream(new BufferedOutputStream(mySocket.getOutputStream()));  
  94.             dout.writeUTF("shutdownOutput后,数据发得得出去吗?");  
  95.             mySocket.shutdownOutput();  
  96.         } catch (IOException e) {  
  97.             e.printStackTrace();  
  98.         }  
  99.     }  
  100. }  



微笑服务器端程序:

 

[java]  view plain  copy
  1. /**    
  2. * @Title: ServerSocketTest.java 
  3. * @Package com.test1 
  4. * @Description: TODO(该文件为”Socket中,流关闭后,发生什么事“的Sever测试端) 
  5. * @author 慢跑学Android 
  6. * @date 2011-11-12 上午11:31:05 
  7. * @version V1.0    
  8. */  
  9. package com.test1;  
  10.   
  11. import java.io.*;  
  12. import java.net.*;  
  13.   
  14. public class ServerSocketTest extends Thread{  
  15.     private ServerSocket myServerSocket;  
  16.     private final int PORT = 9999;  
  17.     public static void main(String[] args){  
  18.         ServerSocketTest sst = new ServerSocketTest();  
  19.         sst.start();  
  20.     }  
  21.       
  22.     public ServerSocketTest(){  
  23.         // 初始化一个ServeSocket端  
  24.         try {  
  25.             myServerSocket = new ServerSocket(PORT);  
  26.         } catch (IOException e) {  
  27.             e.printStackTrace();  
  28.         }  
  29.     }  
  30.       
  31.     public void run(){  
  32.         while(true){  
  33.             System.out.println("我是服务器,我在9999端口监听....");  
  34.             try {  
  35.                 Socket socket = myServerSocket.accept();  
  36.                 DataInputStream din = new DataInputStream(new BufferedInputStream(socket.getInputStream()));  
  37.                 String msgIn = din.readUTF();  
  38.                 System.out.println(msgIn.trim());  
  39.             } catch (IOException e) {  
  40.                 e.printStackTrace();  
  41.             }  
  42.         }  
  43.     }  
  44. }  


说明一点:

在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)

相关文章
|
1月前
|
存储 Java 数据处理
|
1月前
|
Java API
java中IO与NIO有什么不同
java中IO与NIO有什么不同
|
19天前
|
存储 Java
探索 Java IO 流的多种实现方式
【4月更文挑战第4天】Java IO 流是处理输入输出的关键组件,包括文件流(FileInputStream/FileOutputStream)、字符流(FileReader/FileWriter)、缓冲区流(BufferedInputStream/BufferedOutputStream)、转换流(InputStreamReader/OutputStreamWriter)、数据流(DataInputStream/DataOutputStream)、对象流(ObjectInputStream/ObjectOutputStream)、随机访问文件流(RandomAccessFile)和管道流。
|
30天前
|
Java 关系型数据库 MySQL
Flink1.18.1和CDC2.4.1 本地没问题 提交任务到服务器 报错java.lang.NoClassDefFoundError: Could not initialize class io.debezium.connector.mysql.MySqlConnectorConfig
【2月更文挑战第33天】Flink1.18.1和CDC2.4.1 本地没问题 提交任务到服务器 报错java.lang.NoClassDefFoundError: Could not initialize class io.debezium.connector.mysql.MySqlConnectorConfig
49 2
|
1月前
|
Java
|
2月前
|
Java 数据处理
如何玩转Java IO?
【2月更文挑战第7天】
219 0
如何玩转Java IO?
|
2月前
|
Java
[Java]Socket套接字(网络编程入门)
[Java]Socket套接字(网络编程入门)
38 0
|
22小时前
|
安全 Java 调度
Java线程:深入理解与实战应用
Java线程:深入理解与实战应用
7 0
|
5天前
|
安全 Java
深入理解 Java 多线程和并发工具类
【4月更文挑战第19天】本文探讨了Java多线程和并发工具类在实现高性能应用程序中的关键作用。通过继承`Thread`或实现`Runnable`创建线程,利用`Executors`管理线程池,以及使用`Semaphore`、`CountDownLatch`和`CyclicBarrier`进行线程同步。保证线程安全、实现线程协作和性能调优(如设置线程池大小、避免不必要同步)是重要环节。理解并恰当运用这些工具能提升程序效率和可靠性。
|
5天前
|
安全 Java
java多线程(一)(火车售票)
java多线程(一)(火车售票)