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

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

测试三:丢弃

微笑客户端程序:

[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.         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. }  



微笑服务器端程序:

 

[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.         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)

相关文章
|
11天前
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
63 23
|
7天前
|
监控 API 开发工具
Socket.IO介绍,以及怎么连接测试Socket.IO接口?
Socket.IO 是一个用于浏览器和服务器间实时双向通信的库,支持低延迟消息传递、跨平台运行及自动重连。文章介绍了其特点与调试需求,并详细说明如何使用 Apifox 工具创建、连接、发送/接收 Socket.IO 事件,以及团队协作和调试技巧。掌握这些技能可提升实时应用开发效率与质量。
|
1月前
|
缓存 网络协议 Java
JAVA网络IO之NIO/BIO
本文介绍了Java网络编程的基础与历史演进,重点阐述了IO和Socket的概念。Java的IO分为设备和接口两部分,通过流、字节、字符等方式实现与外部的交互。
|
2月前
|
Java 物联网 定位技术
Java socket获取gps定位
通过Java Socket编程获取GPS定位信息可以实现实时的地理位置跟踪。本文介绍了如何搭建Socket服务器、解析GPS数据以及实现客户端发送GPS数据的流程。希望这篇文章能为开发者提供清晰的指导,帮助构建高效的GPS定位系统。
56 7
|
4月前
|
Java
java 中 IO 流
Java中的IO流是用于处理输入输出操作的机制,主要包括字节流和字符流两大类。字节流以8位字节为单位处理数据,如FileInputStream和FileOutputStream;字符流以16位Unicode字符为单位,如FileReader和FileWriter。这些流提供了读写文件、网络传输等基本功能。
79 10
|
5月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
155 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
5月前
|
Java
[Java]Socket套接字(网络编程入门)
本文介绍了基于Java Socket实现的一对一和多对多聊天模式。一对一模式通过Server和Client类实现简单的消息收发;多对多模式则通过Server类维护客户端集合,并使用多线程实现实时消息广播。文章旨在帮助读者理解Socket的基本原理和应用。
56 1
|
5月前
|
Java
Java 中 IO 流的分类详解
【10月更文挑战第10天】不同类型的 IO 流具有不同的特点和适用场景,我们可以根据具体的需求选择合适的流来进行数据的输入和输出操作。在实际应用中,还可以通过组合使用多种流来实现更复杂的功能。
108 0
|
5月前
|
网络协议 测试技术 网络安全
Python编程-Socket网络编程
Python编程-Socket网络编程
54 0
|
8月前
|
网络协议 开发者 Python
深度探索Python Socket编程:从理论到实践,进阶篇带你领略网络编程的魅力!
【7月更文挑战第25天】在网络编程中, Python Socket编程因灵活性强而广受青睐。本文采用问答形式深入探讨其进阶技巧。**问题一**: Socket编程基于TCP/IP,通过创建Socket对象实现通信,支持客户端和服务器间的数据交换。**问题二**: 提升并发处理能力的方法包括多线程(适用于I/O密集型任务)、多进程(绕过GIL限制)和异步IO(asyncio)。**问题三**: 提供了一个使用asyncio库实现的异步Socket服务器示例,展示如何接收及响应客户端消息。通过这些内容,希望能激发读者对网络编程的兴趣并引导进一步探索。
97 4