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次发送数据包的时候抛出异常,结果如下图:
在这里插入图片描述

问题分析

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

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

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

总结

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

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值