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()不会。

测试二:不可以,会抛出异常!

测试三:丢弃

客户端程序:

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();
        }
    }
}

服务器端程序:

/**
* @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)

Reference:

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

时间: 2024-10-17 17:42:16

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

Java中的IO流(五)

上一篇<Java中的IO流(四)>记录了一下Properties类,此类不属于IO流,它属于集合框架.接下来说一下IO流中的其它流 一,打印流PrintStream PrintStream为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式.并且此注永远不会抛出IOException. 此流的构造函数大致分三类 1,接收File文件类型的 2,接收OutputStream类型的 3,接收文件名形式的 下演示一下此流的两个方法 1 private static void functio

JAVA 中的IO流

Java中的IO流是用来处理设备与设备之前的数据传输,在java中以流的形式传输.流分为两类:字节流和字符流. 字节流:InputStream,OutPutSteam.(计算机内的数据都是以字节存储的,字节流可以操作任意数据) 字符流:Reader,Writer.(字符流只能操作字符,但是在实际应用中字符流比较方便) 从操作来看又可以分为:输入流和输出流. 在进行IO流操作的时候分为以下几步:1.导入IO流的包,2.进行IO流的异常处理,3.关闭IO流释放资源. 字节流 ————————————

Java中的IO流总结

Java中的IO流总结 1. 流的继承关系,以及字节流和字符流. 2. 节点流FileOutputStream和FileInputStream和处理流BufferedInputStream和BufferedOutputStream.以及对应的FileOutputWriter,FileInputReader,BufferedInputReader,BufferedOutputWriter. 3. 转换流InputStreamReader和OutputStreamWriter 一:流的继承关系 字节

Java中的IO流之输入流|乐字节

亲爱的乐字节的小伙伴们,小乐又来分享Java技术文章了.上一篇写到了IO流,这篇文章着重 谈谈输入流,再下次再说输出流. 点击回顾上一篇:乐字节Java之file.IO流基础知识和操作步骤 一. 输入流 字节流和字符流的操作方式几乎完全一样,只是操作的数据单元不同而已 .字节流可 以操作所有文件,字符流仅操作纯文本. 1.抽象类:InputStream 和 Reader InputStream和Reader是所有输入流的基类,它们是两个抽象类,是所有输入流的模版,其中定义的方法在所有输入流中都可

Java中的IO流

Java中的IO流是实现输入/输出的基础. 按照流的方向不同:分为输入流和输出流. 按照处理数据单位的不同:分为字节流(8位)和字符流(16位). 按照功能不同:分为节点流和处理流 所有面向字节的流类都继承于InputStream类(输入流) 或OutputStream类(输出流),这两个类是抽象类,我们可以利用它的子类来完成不同的功能. InputStream.OutputStream都是抽象类 InputStream抽象了应用程序读取数据的方式 OutputStream抽象类应用程序写出数据

Java中的IO流(1)

字节流: //一个字节一个字节的读写 FileInputStream in=new FileInputStream("源文件"); FileOutputStream out=new FileOutputStream("目标文件"); ...... in.close(); out.close(); 首先要记住,一旦使用了IO流最后一定要记得关闭,这是常识. //利用缓冲区,高效的读取字节 BufferedInputStream in=new BufferedInput

Java中的IO流体系

Java为我们提供了多种多样的IO流,我们可以根据不同的功能及性能要求挑选合适的IO流,如图10-7所示,为Java中IO流类的体系. 注:这里只列出常用的类,详情可以参考JDK API文档.粗体标注为常用! 图10-7 Java中的IO流体系 从上图发现,很多流都是成对出现的,比如:FileInputStream/FileOutputStream,显然是对文件做输入和输出操作的.我们下面简单做个总结: 1. InputStream/OutputStream 字节流的抽象类. 2. Reader

整理 JAVA中的IO流 (字符流和字节流两个大类)

java中的io流分为两类,字符和字节: OutputStream和InputStream字节流的父类,抽象.OutputStream有两个提供了实现的接口closable和flushable. Writer和Reader字符流的父类,抽象.实际上在流的操作中,底层与文件进行读写的都是字节流,因为即使是字符流的对象,其最终实现读写的也是用的字节流. 操作文件的字节子类FileOutputStream和FileInputStream.记住,这里面写出和读入的都是字节. class useByteS

Java实现文件写入——IO流(输入输出流详解)

输入输出的重要性:     输入和输出功能是Java对程序处理数据能力的提高,Java以流的形式处理数据.流是一组有序的数据序列,根据操作的类型,分为输入流和输出流. 程序从输入流读取数据,向输出流写入数据.Java是面向对象的程序语言,每一个数据流都是一个对象,它们提供了各种支持“读入”与“写入”操作的流类. Java的输入输出功能来自java.io 包中的InputStream类.OutputStream类.Reader类和Writer类以及继承它们的各种子类. (一)解析文件处理的奥秘 1