您的位置:首页 > 编程语言 > Java开发

Java socket中关闭IO流后,发生什么事?(以关闭输出流为例)

2014-07-23 22:09 381 查看
声明:该博文以socket中,关闭输出流为例进行说明。

注意一点:若一端使用 Socket.shutdownOutput() 方法后,另一端使用 DataInputStream.read() 方法的返回值是-1

为了方便讲解,我们把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
plaincopy

package com.test2;

import java.io.*;

import java.net.*;

/**

* @ClassName: SocketTest

* @Description: 测试Socket中,流关闭后,socket是否关闭?是否可重开流?输出缓存区的数据是发送出去,还是丢弃?

* @author 慢跑学Android

* @date 2011-11-12 上午11:15:21

*

*/

public class SocketTest {

Socket mySocket;

DataOutputStream dout;

public static void main(String[] args){

new SocketTest();

}

public SocketTest(){

// 输出流关闭的测试一:socket关闭吗?

test1();

// 输出流关闭测试二:该流是否可以重新开启?

test2();

// 输出流关闭测试三:输出缓冲区里的数据是丢弃,还是发送?

test3();

}

private void test1() {

// 输出流关闭的测试一:socket关闭吗?

System.out.println("\n****2种方式关闭输出流,Socket是否关闭?***\n");

try {

mySocket = new Socket("27.154.122.233",9999);

} catch (UnknownHostException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

try {

dout = new DataOutputStream(new BufferedOutputStream(mySocket.getOutputStream()));

//下面这一句主要是用来证明socket确实处于开启状态

System.out.println("输出流刚打开,Socket是否关闭?" + mySocket.isClosed());

mySocket.shutdownOutput();

System.out.println("使用shutdownOutput关闭输出流,Socket是否关闭?" + mySocket.isClosed());

dout.close();

System.out.println("使用close关闭输出流,Socket是否关闭?" + mySocket.isClosed());

} catch (IOException e) {

e.printStackTrace();

}

}

private void test2() {

// 输出流关闭测试二:使用shutdownOutputStream后,输出流是否可以重新开启?

System.out.println("\n****使用shutdownOutputStream后,输出流是否可以重新开启?***\n");

try {

mySocket = new Socket("27.154.122.233",9999);

} catch (UnknownHostException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

try {

dout = new DataOutputStream(new BufferedOutputStream(mySocket.getOutputStream()));

mySocket.shutdownOutput();

// 重开输出流

dout = new DataOutputStream(mySocket.getOutputStream());

dout.writeUTF("是否允许我重开?");

// 清空输出缓存,确保当dout通道没问题时,消息可以到达服务器

dout.flush();

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

mySocket.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

private void test3(){

// 输出流关闭测试三:输出缓冲区里的数据是丢弃,还是发送?

System.out.println("\n***输出缓冲区里的数据是丢弃,还是发送?****\n");

try {

mySocket = new Socket("27.154.122.233",9999);

} catch (UnknownHostException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

try {

dout = new DataOutputStream(new BufferedOutputStream(mySocket.getOutputStream()));

dout.writeUTF("shutdownOutput后,数据发得得出去吗?");

mySocket.shutdownOutput();

} catch (IOException e) {

e.printStackTrace();

}

}

}


服务器端程序:

[java] view
plaincopy

/**

* @Title: ServerSocketTest.java

* @Package com.test1

* @Description: TODO(该文件为”Socket中,流关闭后,发生什么事“的Sever测试端)

* @author 慢跑学Android

* @date 2011-11-12 上午11:31:05

* @version V1.0

*/

package com.test1;

import java.io.*;

import java.net.*;

public class ServerSocketTest extends Thread{

private ServerSocket myServerSocket;

private final int PORT = 9999;

public static void main(String[] args){

ServerSocketTest sst = new ServerSocketTest();

sst.start();

}

public ServerSocketTest(){

// 初始化一个ServeSocket端

try {

myServerSocket = new ServerSocket(PORT);

} catch (IOException e) {

e.printStackTrace();

}

}

public void run(){

while(true){

System.out.println("我是服务器,我在9999端口监听....");

try {

Socket socket = myServerSocket.accept();

DataInputStream din = new DataInputStream(new BufferedInputStream(socket.getInputStream()));

String msgIn = din.readUTF();

System.out.println(msgIn.trim());

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

说明一点:

在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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: