浅谈java socket的正确关闭姿势
java socket对应的是网络协议中的tcp,tcp的三次握手、四次挥手、11中状态什么的这里就不说了,不知道大家平常使用socket的时候如果不注意的情况下,会不会遇到各种异常报错。
例如:
java.net.SocketException:socket is closed
错误提示的出现场景:
自己主动关闭了socket,但是之后还从里面读写数据
Software caused connection abort: socket write error
错误提示的出现场景:
对方已经关闭socket,依旧向对方写数据
connection reset (by peer)
错误提示出现的场景:
一端socket被关闭,另一端仍然发送数据,发送的第一个数据包 connection reset by peer
一端socket退出,退出时为关闭连接,另一端读数据 connection reset
所以在使用socket时,需要约定好双方读写完成的条件,然后关闭输入输出流:
socket.shutdownInput(); socket.shutdownOutput();
即当一方写入完成后,调用shutdownOutput关闭输出流,这时候对方的read方法就会返回-1,这时候对方就知道你写完了,对方可以关闭输入流,然后等待对方写入完成调用shutdownOutput后己方再调用shutdownInput,双方就正常关闭了输入输出流,这时候socket就不会出现异常了。
下面是一个socket交互的例子:
server端
public class OioServer { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(8080); while (true) { Socket socket = serverSocket.accept(); System.out.println("socket = " + socket); new Thread(() -> { try { InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); out.write("hello! I get your message that is follow".getBytes(Charset.forName("UTF-8"))); byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) != -1) { System.out.print(new String(buf, 0, len, Charset.forName("UTF-8"))); out.write(buf, 0, len); } out.write("\n end \n".getBytes(Charset.forName("UTF-8"))); out.flush(); socket.shutdownInput(); socket.shutdownOutput(); } catch (IOException e) { e.printStackTrace(); }finally { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } }).start(); } } }
client端
public class OioClient { public static void main(String[] args) throws IOException { Socket socket = new Socket("127.0.0.1", 8080); InputStream in = socket.getInputStream(); new Thread(() -> { BufferedInputStream bufferIn = new BufferedInputStream(in); byte[] buf = new byte[1024]; try { int len; while ((len = bufferIn.read(buf)) != -1) { System.out.print(new String(buf, 0, len, Charset.forName("UTF-8"))); } }catch (Exception e) { e.printStackTrace(); } try { socket.shutdownInput(); socket.close(); } catch (IOException e) { e.printStackTrace(); } }).start(); OutputStream out = socket.getOutputStream(); int cout = 10; while (cout-- > 0) { out.write(("this time is " + System.currentTimeMillis() + "\n").getBytes("UTF-8")); } socket.shutdownOutput(); } }
java socket - 半关闭
通常,使用关闭输出流来表示输出已经结束。但在进行网络通信时则不能这样做。因为我们关闭输出流时,该输出流对应的Socket也将随之关闭,这样程序将无法再从该socket中读取数据。
为了应付这种情况,socket提供了两个半关闭的方法用来只关闭socket的输入流或者输出流,用以表示输出数据已经发送完成。
方法详情:
shutdownInput():关闭该socket的输入流,程序还可以通过该socket的输出流输出数据;
shutdownOutput():关闭该socket的输出流,程序还可以通过该socket的输入流读取数据。
当调用shutdownInput()或shutdownOutput()方法关闭输入流或输出流后,该socket处于半关闭状态。
此时可以使用isInputShutdown()或isOutputShutdown()来判断该socket是否处于半读状态或半写状态。
需要注意的是,即使同一个socket先后调用shutdownInput()和shutdownInput()方法,该socket实例仍然没有被关闭,只是该socket既不能输出数据也不能读取数据而已。
当调用shutdownInput()或shutdownOutput()方法关闭了输入流或输出流之后,该socket无法再次打开输出流或输入流,因此这种做法不适合需要保持持久通信状态的交互式应用。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
详解Spring注解--@Autowired、@Resource和@Service
本篇文章主要介绍最重要的三个Spring注解,也就是@Autowired、@Resource和@Service,具有很好的参考价值。下面跟着小编一起来看下吧2017-05-05使用JSONObject.toJSONString 过滤掉值为空的key
这篇文章主要介绍了使用JSONObject.toJSONString 过滤掉值为空的key,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2022-03-03将ResultSet中得到的一行或多行结果集封装成对象的实例
这篇文章主要介绍了将ResultSet中得到的一行或多行结果集封装成对象的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2020-05-05Spring Boot利用Docker快速部署项目的完整步骤
这篇文章主要给大家介绍了关于Spring Boot利用Docker快速部署项目的完整步骤,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring Boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧2019-07-07亲手教你IDEA2020.3创建Javaweb项目的步骤详解
这篇文章主要介绍了IDEA2020.3创建Javaweb项目的步骤详解,本文是小编手把手教你,通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧2021-03-03
最新评论