ServerSocket连接断开处理方式
- 1、概述:
- 2、异常信息:
- 3、代码分析
- 4、场景分析
- 4.1.建立Socket连接,底层就是TCP连接:
- 4.2.发送数据
- 4.3.断开连接
- 5、总结:
1、概述:
WebSocket是一种在单个TCP连接上进行全双工通信的协议。在我们应用的过程仲,客户端会出现无故断开的情况。这里提供一种连接断开的异常检测机制。
2、异常信息:
系统中出现的异常
2019-03-12 18:56:24,044 ERROR [com.lenovo.SocketServer.ping(172)] -
2019-03-12 18:56:24,045 ERROR [com.lenovo.SocketServer.ping(173)] -
2.1、之前有人给出的方案:
总结产生原因,在服务端/客户端单方面关闭连接的情况下,另一方依然以为tcp连接仍然建立,试图读取对方的响应数据,导致出现Software caused connection abort: recv failed的异常。 通过inputstream的available()方法来判断,是否有响应结果。但是对SocketInputStream没有效果,因为SocketInputStream 在断开连接和数据正常传输状态的下 available 返回值都是0。
3、代码分析
其中InputStream 类型为 SocketInputStream,但是SocketInputStream 在 jdk 的rt.jar 中,是JDK的核心专用类型,不是public类型,只能通过反射获取其中的参数。 有一行代码:boolean eof = (Boolean) getValueByKey(inputStream, “eof”);获取eof 字段的值就是通过Java 的反射机制做的。下面会重点说这个字段。
开启WebSocket服务端:
private static void generateTCPServer() throws IOException{ServerSocket serverSocket = new ServerSocket(12345);while (true){Socket socket = serverSocket.accept();Thread thread = new Thread(){@Overridepublic void run(){System.out.println("开启新的线程"); while (true){try {if (socket == null){System.out.println("socket为null");Thread.interrupted();}else{boolean flag = handler(socket);if(!flag){System.out.println("Client Down");Thread.interrupted();break;}Thread.sleep(50);}}catch (Exception e){logger.error("System error");logger.error(e.getMessage());e.printStackTrace();}}}};thread.start();}}
连接数据处理逻辑:
public static boolean handler(Socket socket) {try {OutputStream outputStream = socket.getOutputStream();InputStream inputStream = socket.getInputStream();byte[] b = new byte[51200];inputStream.read(b);boolean eof = (Boolean) getValueByKey(inputStream, "eof");if (true == eof) {logger.error("");return false;}String msg = CommonUtil.toHexString(b);String head = msg.substring(0, 2);if (head.equals("00")) {logger.error("");return false;}} catch (IOException e) {logger.error("IOException by TCP");logger.error(e);}return true;}
4、场景分析
4.1.建立Socket连接,底层就是TCP连接:
连接过程代码走到 inputStream.read(b);就I/O中断了 并等待请求数据过来,继续执行下面的代码。new byte[51200] 为下一次请求建立了一缓存区,用于接收下一次请求的数据。
这里Thread的状态仍然是RUNNABLE。
发起连接请求:响应 为空
流程处理过程中部分核心参数:
OutputStreamappend:falsechannel:nullclosed:falseclosing:falsesocket:bound:truecreated:trueconnected:trueclosed:falseInputStreamchannel:nullclosed:false closing:falseeof:false =========== 不一样的地方socket:bound:truecreated:trueconnected:trueclosed:false
4.2.发送数据
代码从连接检测的代码处继续执行,一直到返回响应结束。
// 第一种方式:通过获取eof 参数获取当前连接是否断开的参数
boolean eof = (Boolean) getValueByKey(inputStream, “eof”);
流程处理过程中部分核心参数:如果连接没有断开,就是上一次请求结束后的参数。
OutputStreamappend:falsechannel:nullclosed:falseclosing:falsesocket:bound:truecreated:trueconnected:trueclosed:falseInputStreamchannel:nullclosed:false closing:falseeof:false =========== 不一样的地方socket:bound:truecreated:trueconnected:trueclosed:false
4.3.断开连接
代码从连接检测的代码处继续执行,但是在连接断开检测的时候就结束了 并返回false。
// 第一种方式:通过获取eof 参数获取当前连接是否断开的参数
boolean eof = (Boolean) getValueByKey(inputStream, “eof”);
以下两种方式中的任意一种都可以作为连接断开检测代码,推荐第一种:
流程处理过程中部分核心参数:连接断开后eof为true.
OutputStreamappend:falsechannel:nullclosed:falseclosing:falsesocket:bound:truecreated:trueconnected:trueclosed:falseInputStreamchannel:nullclosed:false closing:falseeof:true ============不一样的地方socket:bound:truecreated:trueconnected:trueclosed:false
5、总结:
优先通过连接状态来判断客户端是否断开。需要建立一种异常检测机制和连接重连的机制。