开发者社区> 一叶飘舟> 正文

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)

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
27728 0
Databricks数据洞察公测实例关闭通知
9月底Databricks已经正式提供商业版服务,11月10日将关闭公测实例,请公测客户务必提前做好数据备份,感谢大家
357 0
Java网络编程从入门到精通(27):关闭服务端连接
本文为原创,如需转载,请注明作者和出处,谢谢! 上一篇:Java网络编程从入门到精通(26):在服务端接收和发送数据     在客户端和服务端的数据交互完成后,一般需要关闭网络连接。
898 0
Java IO流关闭问题之原理简析
当有嵌套的流时即流被封装,在关闭的时候无论是关闭最外面的还是最里面的都是一样的,因为最外面的包装流的close的方法其实就是调的最里面的流的close方法。所以择其一关闭即可。参考链接:https://blog.
989 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
19980 0
+关注
1635
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载