Window系统 Socket编程发送心跳排坑记录(socket.sendUrgentData)

排坑背景

在工作中两个部门避免不了相互协作进行开发,开发过程中会遇到很多问题,当出现两遍代码都没问题的场景,有时会出现互相推诿的现象,那么我们如何去解决问题成为了关键。

场景描述

在socket编程中除了需要发送业务报文,有时还需要发送心跳进行检测,然后进行重连机制。在工作中我们的场景是A系统调用B系统,B系统返回的报文需要调用C系统进行签名,然后返回给A系统。B系统调用C系统使用的是Socket方式调用获取进行签名。当B系统发送心跳到C系统,一段时间后会断开连接抛出异常,两端开发人员都认为是对方的问题,因为谁都没有主动关闭连接,并且网络没有问题,那么排坑过程开始了,下面模拟客户端和服务端代码在本地window 7系统进行演示。

服务端代码

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author Ryan
 * @date 2018-11-28.
 */
public class SocketServer {

    public static void main(String[] args) {
        try {
            // 创建socket服务端,端口为15000
            ServerSocket serverSocket = new ServerSocket(15000);
            while (true){
                //此方法为阻塞方法,用户等待客户端连接
               Socket socket =  serverSocket.accept();
                InputStream inputStream = socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream();
                InputStreamReader in = new InputStreamReader(inputStream);
                BufferedReader reader = new BufferedReader(in);
                boolean flag =true;
                while (flag){
                    String info = reader.readLine();
                    if(info.endsWith("end")){
                        System.out.println("客户端说:"+info);
                        flag = false;
                    }
                }
                PrintWriter writer = new PrintWriter(outputStream);
                writer.write("我是服务端,hello");
                writer.flush();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端代码

import java.net.Socket;

/**
 * @author Ryan
 * @date 2018-11-28.
 */
public class SocketClient {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("127.0.0.1",15000);
            //i用于记录多少次时断开连接
            int i=1;
            while (true){
                System.out.println("发送心跳"+i++);
                socket.sendUrgentData(0xff);
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

socket.sendUrgentData(0xff)方法用于向服务端发送紧急数据包,如果服务端Socket的SO_OOBINLINE属性没有打开,就会自动舍弃这个字节,而SO_OOBINLINE属性默认情况下就是关闭的。所以我们使用此方法进行数据心跳检查。

问题描述

当启动客户端和服务端服务后,客户端每秒会向客户端发送紧急数据包,当第18次发送数据包的时候抛出异常,结果如下图:
Window系统 Socket编程发送心跳排坑记录(socket.sendUrgentData)_第1张图片

问题分析

出现这个问题后,如果在不知道原因时,客户端代码和服务端代码都没有问题,导致B系统人员和C系统人员相互推诿,那么这个时候我们可以使用Wireshark工具抓包分析是哪个服务关闭了连接。
截图如下:
在这里插入图片描述

根据截图可知服务端返回了RST包,因此说明是服务端进行关闭连接,所以是C系统的问题。因此推锅结束。
但是C系统的代码确实没有问题,所以虽然推锅成功,但是依然需要解决对应的问题,在测试的过程中发现每次都是第18次的时候断开,因此度娘,谷哥搜索了以便发现了一篇文章
1.socket.sendUrgentData在windows7下出现17次失效的问题
2.TCP Connection is reset after sending urgent data

因此得出是window系统的问题。

总结

排坑的过程是痛苦的,所以要耐心的去分析,哪怕是走弯路,但最终是有收获的。建议不使用sendUrgentData进行发送心跳检查,服务端可以接收特殊报文,用于检查连接是否断开。
另外由于资源有限,只验证了win7系统,有兴趣的朋友可以留言发布你的系统是否会出现,实践了才知道别人说的是否正确。后续本人有时间也会进行验证。

你可能感兴趣的:(排坑记录)