java - 发送ACK会大大减慢数据传输速度

标签 java android sockets tcp

意识到 TCP 校验和实际上是一个非常差的校验和,促使我在数据 block 中包含一个额外的校验和 (SHA-256),以验证服务器上数据的完整性,并在损坏的情况下请求数据再次阻止。但ACK的加入大大降低了数据传输速率。就我而言(数据通过 wifi 传输),速度从 ~90mbps 下降到 ~12mbps。

客户:

SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("192.168.31.30", 3333));
ByteBuffer byteBufferData = ByteBuffer.allocateDirect(1024 * 8);
ByteBuffer byteBufferACK = ByteBuffer.allocateDirect(1);
for (int i = 0; i < 1024; i++) {
    // write data (payload + checksum (SHA-256))
    socketChannel.write(byteBufferData);
    byteBufferData.clear();
    // read ACK
    socketChannel.read(byteBufferACK);
    byteBufferACK.clear();
    // if (byteBufferACK.get() == XXX)
        // ... retransmission byteBufferData
}

服务器:

    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.socket().bind(new InetSocketAddress(3333));
    SocketChannel socketChannel = serverSocketChannel.accept();
    ByteBuffer byteBufferData = ByteBuffer.allocateDirect(1024 * 8);
    ByteBuffer byteBufferACK = ByteBuffer.allocateDirect(1);
    long startTime = System.currentTimeMillis();
    while ((socketChannel.read(byteBufferData)) != -1) {
        // when 8192 bytes of data were read
        if (!byteBufferData.hasRemaining()) {
            byteBufferData.clear();
            // write ACK
            socketChannel.write(byteBufferACK);
            byteBufferACK.clear();
        }
    }
    System.out.println(System.currentTimeMillis() - startTime);

请注意,该代码是测试代码,并不旨在传达任何有用的数据。它仅用于测试数据传输速率。

我有两个问题:

  1. 也许我不明白某些事情或者做得不正确,但是为什么发送一个字节的数据作为数据接受确认(ACK)对整体数据传输速率影响如此之大?如何避免这种情况?
  2. SHA-256 足以作为 8kb 大小的数据的校验和吗? (在现有的 TCP CRC 之上)

最佳答案

因为你在等待。假设您和服务器之间有 200 毫秒的延迟。如果没有确认,您将尽快写入数据包,使带宽饱和,然后停止。有了 ack,它看起来像这样:

t=0  send 1st 8k
t=200 server recieves
t=205ish  server sends ack
t=405 client recieves ack.
t=410ish client sends 2nd 8k

你浪费了 50% 的发送时间。事实上,我很惊讶它并没有变得更糟。

TCP 有很多功能可以防止此类问题,包括数据滑动窗口(您不会发送一个数据包并确认它,而是发送 N 个数据包,然后服务器确认它收到的数据包,从而允许丢失数据包将按顺序重新发送)。您正在糟糕地重新实现 TCP,而且几乎肯定不应该这样做。

如果您打算这样做,请不要使用 TCP。使用 UDP 或原始套接字并在其上编写新协议(protocol)。您仍在使用 TCP 确认和校验和,因此您的是多余的。

关于java - 发送ACK会大大减慢数据传输速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48115706/

相关文章:

android - 我如何从自定义 View 中获取宽度和高度尺寸?

c# - UDP:从所有网络接口(interface)读取数据

java - 什么是实现套接字的好方法?

Java死锁问题

java - 如何在 Java 中包含度数和分钟符号?

Java编程银行账户代码

android - CSS:适用于各种移动设备的字体大小、物理按钮高度

安卓超时错误

java jersey 获取完整的 URL

java - 使用 Java Nashorn 加载 'quests'