在Java/Android中更快地检测到损坏的套接字

Nic*_* A. 10 java networking android tcp

背景

我的应用程序从手机收集数据并将其发送到远程服务器.
数据首先存储在内存中(或者当文件足够大时存储在文件中),每隔X秒左右,应用程序就会刷新该数据并将其发送到服务器.

关键是每一条数据都成功发送,我宁愿发送两次数据而不是发送数据.

问题

作为测试,我将应用程序设置为每5秒发送一个带有时间戳的数据,这意味着服务器上每5秒出现一个新行.
如果我杀了服务器,我希望线路停止,现在应该将它们写入内存.

当我再次启用服务器时,我应该能够确认没有任何事件丢失.

然而问题是,当我杀死服务器时,IO操作开始失败大约需要20秒,这意味着在这20秒内,应用程序会愉快地发送事件并将其从内存中删除,但它们永远不会到达服务器并永远丢失.

我需要一种方法来确保数据实际到达服务器.

这可能是最基本的TCP问题之一,但并非如此,我还没有找到任何解决方案.

我试过的东西

附加信息

我无法改变服务器如何响应意味着我无法告诉服务器确认数据(不仅仅是TCP的机制),服务器只是默默地接受数据而不发回任何东西.

代码片段

课程初始化:

socket = new Socket(host, port);
socket.setTcpNoDelay(true);
Run Code Online (Sandbox Code Playgroud)

数据发送的位置:

while(!dataList.isEmpty()) {
    String data = dataList.removeFirst();
    inMemoryCount -= data.length();
    try {
        OutputStream os = socket.getOutputStream();
        os.write(data.getBytes());
        os.flush();
    }
    catch(IOException e) {
        inMemoryCount += data.length();
        dataList.addFirst(data);
        socket = null;
        return false;
    }
}

return true;
Run Code Online (Sandbox Code Playgroud)

更新1

我再说一遍,我无法改变服务器的行为方式.
它通过TCP和UPD接收数据,并且不会发送任何数据以确认接收.这是一个事实,并且在一个完美的世界中,服务器会确认数据,但这根本不会发生.


更新2

Fraggle发布的解决方案非常完美(关闭套接字并等待输入流关闭).

然而,这带来了一系列新问题.
由于我在手机上,我必须假设用户无法发送无限量的字节,并且我希望尽可能将所有数据流量保持在最低限度.

我不担心打开一个新套接字的开销,这几个字节不会有所作为.然而,我担心的是,每次我连接到服务器时,我都必须发送一个短字符串来标识我是谁.

字符串本身不是那么长(大约30个字符)但如果我经常关闭并打开套接字会增加.

一种解决方案只是每隔X字节"刷新"一次数据,问题是我必须明智地选择X; 如果太大,如果套接字发生故障,将发送过多的重复数据,如果它太小,则开销太大.


最后更新

我的最终解决方案是通过每X字节关闭它来"刷新"套接字,如果一切都不顺利,那么X字节将再次发送.

这可能会在服务器上创建一些重复事件,但可以在那里进行过滤.

Fra*_*gle 2

请参阅此处接受的答案:Java Sockets and Dropped Connections

  1. socket.shutdownOutput();
  2. 等待 inputStream.read() 返回 -1,表示对等方也已关闭其套接字