• 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("
    ****2种方式关闭输出流,Socket是否关闭?***
    ");
            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("
    ****使用shutdownOutputStream后,输出流是否可以重新开启?***
    ");
            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("
    ***输出缓冲区里的数据是丢弃,还是发送?****
    ");
            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流后,发生什么事?(以关闭输出流为例)

  • 相关阅读:
    rpm常见命令使用说明
    终端传值给Makefile、Makefile传值给C++代码
    redis实现异步队列
    redis实现分布式锁
    正则表达式
    nginx安装
    metaq
    zeromq
    ActiveMq
    http压力测试
  • 原文地址:https://www.cnblogs.com/549294286/p/3947767.html
Copyright © 2020-2023  润新知