声明:该博文以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()不会。
测试二:不可以,会抛出异常!
测试三:丢弃
客户端程序:
01.package com.test2; 02.import java.io.*; 03.import java.net.*; 04./** 05.* @ClassName: SocketTest 06.* @Description: 测试Socket中,流关闭后,socket是否关闭?是否可重开流?输出缓存区的数据是发送出去,还是丢弃? 07.* @author 慢跑学Android 08.* @date 2011-11-12 上午11:15:21 09.* 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.}
服务器端程序:
01./** 02.* @Title: ServerSocketTest.java 03.* @Package com.test1 04.* @Description: TODO(该文件为”Socket中,流关闭后,发生什么事“的Sever测试端) 05.* @author 慢跑学Android 06.* @date 2011-11-12 上午11:31:05 07.* @version V1.0 08.*/ 09.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)