声明:该博文以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. "\n****2种方式关闭输出流,Socket是否关闭?***\n");
30. try {
31. 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. new DataOutputStream(new BufferedOutputStream(mySocket.getOutputStream()));
40. //下面这一句主要是用来证明socket确实处于开启状态
41. "输出流刚打开,Socket是否关闭?" + mySocket.isClosed());
42. mySocket.shutdownOutput();
43. "使用shutdownOutput关闭输出流,Socket是否关闭?" + mySocket.isClosed());
44. dout.close();
45. "使用close关闭输出流,Socket是否关闭?" + mySocket.isClosed());
46. catch (IOException e) {
47. e.printStackTrace();
48. }
49. }
50.
51. private void test2() {
52. // 输出流关闭测试二:使用shutdownOutputStream后,输出流是否可以重新开启?
53. "\n****使用shutdownOutputStream后,输出流是否可以重新开启?***\n");
54. try {
55. 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. new DataOutputStream(new BufferedOutputStream(mySocket.getOutputStream()));
64. mySocket.shutdownOutput();
65. // 重开输出流
66. new DataOutputStream(mySocket.getOutputStream());
67. "是否允许我重开?");
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. "\n***输出缓冲区里的数据是丢弃,还是发送?****\n");
84. try {
85. 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. new DataOutputStream(new BufferedOutputStream(mySocket.getOutputStream()));
94. "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. new ServerSocketTest();
19. sst.start();
20. }
21.
22. public ServerSocketTest(){
23. // 初始化一个ServeSocket端
24. try {
25. new ServerSocket(PORT);
26. catch (IOException e) {
27. e.printStackTrace();
28. }
29. }
30.
31. public void run(){
32. while(true){
33. "我是服务器,我在9999端口监听....");
34. try {
35. Socket socket = myServerSocket.accept();
36. 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)