在做网络通信时,我们在关闭链接时是选择Socket.close()还是OutputStreamWriter.cloer()?
如果使用Socket.close().会导致数据的丢失的。
看看官方文档上的解释:
Socket.close()
Closes this socket.
Any thread currently blocked in an I/O operation upon this socket will throw a SocketException
.
Once a socket has been closed, it is not available for further networking use (i.e. can't be reconnected or rebound). A new socket needs to be created.
Closing this socket will also close the socket's InputStream
and OutputStream
.
If this socket has an associated channel then the channel is closed as well.
关闭socket.
再次socket基础上阻塞的所有输入输出操作会抛出异常。
一旦一个socket被关闭,它不可以被再次使用(比如重新连接).你需要重新创建一个socket.
关闭socket会关闭它的InputStream和OutputStream。
如果socket和一个channel有关联,这个channel也会自动关闭。
OutputStreamWriter. close()
Closes the stream, flushing it first. Once the stream has been closed, further write() or flush() invocations will cause an IOException to be thrown. Closing a previously closed stream has no effect.
关闭流,清空缓冲区(意思就是把缓冲区剩余的数据继续发送出去)。当流被关闭时,write()和flush()函数都会引起异常抛出。关闭一个已经关闭的流没有效果。
从官方文档可以看到,OutpuStreamWriter.close()会将缓冲区剩下的数据发送出去,那么Socket.close()呢,上面的描述中没有说它会清空缓冲区,但是有一句“关闭socket会关闭它的InputStream和OutputStream”,我们看看关闭OutputStream会不会清空缓冲区,如果不会,说明Socket.close()不会清空缓冲区。
官方文档:
OutputStream.close()Closes this output stream and releases any system resources associated with this stream. The general contract of
close
is that it closes the output stream. A closed stream cannot perform output operations and cannot be reopened.
关闭输出流,释放所有相关系统资源。最普通的合约就是关闭输出流。一个被关闭的输出流不可以进行输出操作和重新启用。
OutputStream.close()也不会释放缓冲区的内容。
总结一下,如果你使用了OutputStreamWriter作为socket通信的组件,千万不要直接关闭socket。直接关闭socket会导致缓冲区中的数据丢失而发送不到接受者。所以建议使用OutputStreamWriter.close()。这样不会导致数据的丢失。
其实使用Socket.close() 也是可以的,但是一定要在Socket.close()之前,先使用OutputStreamWriter.flush(),发送完缓冲区内的数据。保证数据完整。
如果还是不能理解,我下面给出一个实验代码。
需要新建两个类,服务器类:Server.java,客户端类Client.java
Server.java代码:
import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws IOException { ServerSocket server=new ServerSocket(8002); System.out.println("listening....."); Socket client=server.accept(); System.out.println("accept"); InputStream is=client.getInputStream(); byte[] buf=new byte[1000]; int read; while((read=is.read(buf))!=-1) { System.out.write(buf,0,read); } } }
Client.java代码:
import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.Socket; import java.net.UnknownHostException; public class Client { public static void main(String[] args) throws UnknownHostException, IOException { Socket socket=new Socket("127.0.0.1",8002); OutputStream os=socket.getOutputStream(); OutputStreamWriter osw=new OutputStreamWriter(os,"utf-8"); osw.write("a"); //第一次试验使用socket.close() socket.close(); //第二次试验请将socket.close()注释,将下一行注释取消,采用OutputStreamWrite.close() //osw.close(); //加上无限循环防止因为进程结束导致socket自动释放 while(true) { } }
第一次:
启动Server.java,启动Client.java,发现Server.java接受不到发送的"a"。
第二次:
启动Server.java,将Client.java由socket.close()改为osw.close(),启动Client.java,发现服务端收到了发送的"a"。
实验完毕。相信大家已经能看懂了。