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)

相关文章
|
22天前
|
Java
java 中 IO 流
Java中的IO流是用于处理输入输出操作的机制,主要包括字节流和字符流两大类。字节流以8位字节为单位处理数据,如FileInputStream和FileOutputStream;字符流以16位Unicode字符为单位,如FileReader和FileWriter。这些流提供了读写文件、网络传输等基本功能。
41 9
|
2月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
88 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
2月前
|
Java 流计算
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
45 1
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
|
2月前
|
Java
[Java]Socket套接字(网络编程入门)
本文介绍了基于Java Socket实现的一对一和多对多聊天模式。一对一模式通过Server和Client类实现简单的消息收发;多对多模式则通过Server类维护客户端集合,并使用多线程实现实时消息广播。文章旨在帮助读者理解Socket的基本原理和应用。
30 1
|
2月前
|
Java 数据处理 开发者
揭秘Java IO流:字节流与字符流的神秘面纱!
揭秘Java IO流:字节流与字符流的神秘面纱!
40 1
|
2月前
|
自然语言处理 Java 数据处理
Java IO流全解析:字节流和字符流的区别与联系!
Java IO流全解析:字节流和字符流的区别与联系!
98 1
|
2月前
|
Java
Java 中 IO 流的分类详解
【10月更文挑战第10天】不同类型的 IO 流具有不同的特点和适用场景,我们可以根据具体的需求选择合适的流来进行数据的输入和输出操作。在实际应用中,还可以通过组合使用多种流来实现更复杂的功能。
63 0
|
2月前
|
存储 Java 程序员
【Java】文件IO
【Java】文件IO
39 0
|
6月前
|
缓存 监控 Java
Java Socket编程最佳实践:优化客户端-服务器通信性能
【6月更文挑战第21天】Java Socket编程优化涉及识别性能瓶颈,如网络延迟和CPU计算。使用非阻塞I/O(NIO)和多路复用技术提升并发处理能力,减少线程上下文切换。缓存利用可减少I/O操作,异步I/O(AIO)进一步提高效率。持续监控系统性能是关键。通过实践这些策略,开发者能构建高效稳定的通信系统。
184 1
|
6月前
|
IDE Java 开发工具
从零开始学Java Socket编程:客户端与服务器通信实战
【6月更文挑战第21天】Java Socket编程教程带你从零开始构建简单的客户端-服务器通信。安装JDK后,在命令行分别运行`SimpleServer`和`SimpleClient`。服务器监听端口,接收并回显客户端消息;客户端连接服务器,发送“Hello, Server!”并显示服务器响应。这是网络通信基础,为更复杂的网络应用打下基础。开始你的Socket编程之旅吧!
102 3