ServerSocket连接断开处理方式
- 1、概述:
- 2、异常信息:
- 2.1、之前有人给出的方案:
- 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)] - <java.SocketException: Software caused connection abort: recv failed>
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()
{
@Override
public 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);
// 第一种方式:通过获取eof 参数获取当前连接是否断开的参数
boolean eof = (Boolean) getValueByKey(inputStream, "eof");
if (true == eof) {
// 已经断开
logger.error("");
return false;
}
// 第二种方式:获取传输的内容
String msg = CommonUtil.toHexString(b);
String head = msg.substring(0, 2);
// client断开
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。
发起连接请求:响应 为空
流程处理过程中部分核心参数:
OutputStream
append:false
channel:null
closed:false
closing:false
socket:
bound:true
created:true
connected:true
closed:false
InputStream
channel:null
closed:false
closing:false
eof:false =========== 不一样的地方
socket:
bound:true
created:true
connected:true
closed:false
4.2.发送数据
代码从连接检测的代码处继续执行,一直到返回响应结束。
// 第一种方式:通过获取eof 参数获取当前连接是否断开的参数
boolean eof = (Boolean) getValueByKey(inputStream, “eof”);
流程处理过程中部分核心参数:如果连接没有断开,就是上一次请求结束后的参数。
OutputStream
append:false
channel:null
closed:false
closing:false
socket:
bound:true
created:true
connected:true
closed:false
InputStream
channel:null
closed:false
closing:false
eof:false =========== 不一样的地方
socket:
bound:true
created:true
connected:true
closed:false
4.3.断开连接
代码从连接检测的代码处继续执行,但是在连接断开检测的时候就结束了 并返回false。
// 第一种方式:通过获取eof 参数获取当前连接是否断开的参数
boolean eof = (Boolean) getValueByKey(inputStream, “eof”);
以下两种方式中的任意一种都可以作为连接断开检测代码,推荐第一种:
流程处理过程中部分核心参数:连接断开后eof为true.
OutputStream
append:false
channel:null
closed:false
closing:false
socket:
bound:true
created:true
connected:true
closed:false
InputStream
channel:null
closed:false
closing:false
eof:true ============不一样的地方
socket:
bound:true
created:true
connected:true
closed:false
5、总结:
优先通过连接状态来判断客户端是否断开。需要建立一种异常检测机制和连接重连的机制。
发布评论