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有什么不同
|
26天前
|
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
46 2
|
1月前
|
Java
|
2月前
|
Java 数据处理
如何玩转Java IO?
【2月更文挑战第7天】
218 0
如何玩转Java IO?
|
2月前
|
Java
[Java]Socket套接字(网络编程入门)
[Java]Socket套接字(网络编程入门)
38 0
|
2月前
|
缓存 分布式计算 Java
Java基础深化和提高-------IO流
Java基础深化和提高-------IO流
108 0
|
8天前
|
安全 Java 数据处理
Python网络编程基础(Socket编程)多线程/多进程服务器编程
【4月更文挑战第11天】在网络编程中,随着客户端数量的增加,服务器的处理能力成为了一个重要的考量因素。为了处理多个客户端的并发请求,我们通常需要采用多线程或多进程的方式。在本章中,我们将探讨多线程/多进程服务器编程的概念,并通过一个多线程服务器的示例来演示其实现。
|
8天前
|
程序员 开发者 Python
Python网络编程基础(Socket编程) 错误处理和异常处理的最佳实践
【4月更文挑战第11天】在网络编程中,错误处理和异常管理不仅是为了程序的健壮性,也是为了提供清晰的用户反馈以及优雅的故障恢复。在前面的章节中,我们讨论了如何使用`try-except`语句来处理网络错误。现在,我们将深入探讨错误处理和异常处理的最佳实践。
|
12天前
|
网络协议 程序员 Python
pythonTCP客户端编程创建Socket对象
【4月更文挑战第6天】本教程介绍了TCP客户端如何创建Socket对象。Socket作为网络通信的基础单元,包含协议、IP地址和端口等信息。在TCP/IP中,Socket分为流式(TCP)、数据报(UDP)和原始套接字。以Python为例,创建TCP Socket对象需调用`socket.socket(AF_INET, SOCK_STREAM)`。为确保健壮性,应使用异常处理处理可能的`socket.error`。学习本教程将帮助你掌握TCP客户端创建Socket对象的技能。