【问题标题】:Inconsistent socket latency between ESP32 and Kotlin serverESP32 和 Kotlin 服务器之间的套接字延迟不一致
【发布时间】:2020-11-26 05:00:04
【问题描述】:

上下文:

  • 我有一个服务器 (Mac Mini) 和一个客户端 (ESP32),它们通过 WifiClient 类的套接字连接进行通信。
  • 服务器通过以太网连接到路由器,客户端使用 2.4ghz WiFi 连接到路由器。
  • 服务器是用 Kotlin 编写的,并使用默认的 Java 套接字实现。
  • 客户端将使用 FastLED 库将颜色分配给 Neopixel LED(分别为 LED 1 和 2)。

为了测试,服务器每秒以 60 次交替模式发送 FF0000|FF00000000FF|0000FF(作为字符串)。这个测试效果很好,因为如果颜色以每秒 60 次的速度更新,LED 应该看起来是紫色的。如果系统表现不佳,那么我会看到各个颜色。

Client Github RepoServer Github Repo 了解更多上下文。

问题:

我非常清楚地看到蓝色、红色和紫色交替出现。这告诉我某处存在性能问题,但也有短暂时刻它按预期执行。

我的发现:

我一直在记录读取客户端上每条消息所需的时间:

std::string SocketManager::getNextCommand()
{
    unsigned long start = micros();

    // TODO: Flush isn't working
    // flush(): fail on fd 56, errno: 11, "No more processes"
    // client.flush();

    // We need to read in our next command; wait until command is available.
    String message;
    while (client.connected() && message.length() == 0)
    {
        message = client.readStringUntil('\n');
    }

    unsigned long end = micros();
    Serial.print("Time: ");
    Serial.println(end - start);

    return message.c_str();
}

打印出来的时间通常很好,但我会遇到大约每秒 10 次的周期性峰值。我已将日志添加到 Pastebin here

当我第一次看到这个时,我以为客户端缓冲区已经饱和了。然后我将服务器上的消息速率降低到每秒 2 次,但我仍然看到消息时间的显着变化。该日志是here

每当服务器发送消息以验证它是否以正确的速率写入时,我都会打印出系统时间。每秒更新 2 次始终会产生 500 毫秒的间隙,因此我认为排除服务器是合理的。这表明问题出在传输时间或 ESP32(考虑到服务器以指定的时间间隔发布)。

当套接字未激活时,两个设备之间的 ping 为 5-10ms,但当套接字激活时为 50-400+……即使我没有来回发送任何消息!哎呀——即使我完全注释掉客户端的 while 循环(即它立即返回一个空字符串),它也这么高。

问题:

看来我的核心问题是套接字处于活动状态时设备之间的延迟。至少 - 套接字处于活动状态时的 ping 增加似乎在尝试读取下一个命令时延迟增加的范围内。

你认为套接字是这里的主要问题吗?如果是这样 - 为什么?

我觉得奇怪的是,仅仅由于套接字处于活动状态就会发生如此巨大的延迟增加......尤其是在没有来回传输任何大量数据的情况下。

【问题讨论】:

    标签: c++ sockets kotlin arduino esp32


    【解决方案1】:

    我根据this thread设置了性能偏好并禁用了服务器套接字连接上的TCP延迟。

    在服务器代码中,我将 ServerSocket 性能首选项设置为 1、2、0。

    val server = ServerSocket(9999)
    server.setPerformancePreferences(1, 2, 0)
    

    我还禁用了连接上的 TCP 延迟。

    while (true) {
        val client = server.accept()
        println("Client connected: ${client.inetAddress.hostAddress}")
    
        client.soTimeout = 1000
        client.tcpNoDelay = true;
    
        // Run client in it's own thread.
        thread { ClientHandler(client).run() }
    }
    

    这似乎有了很大的改进。肯定有一些时候灯光(大部分)是紫色的。似乎延迟会随着时间的推移而降低,并且连接可能会中断,因此仍然需要进行微调。

    所以 - 我认为这个问题基本上已经解决了(通过一些微调)。尽管如此,我仍然会感谢任何人提供的任何进一步的意见。

    【讨论】:

    • 我脑子里突然冒出几个想法:你有没有办法查看你是否收到了很多 TCP 重传?您是否有办法查看使用 String 类是否会减小堆上最大可分配连续内存的大小?您是否有与 UDP 相同的性能问题(无重传,无 ACK)?
    • (我对网络不是特别精通,所以请多多包涵。)我安装了 Wireshark 并且能够观察服务器和客户端之间的流量。而且,果然,我确实偶然发现了重传。事实上——我记录了一个极端的例子,颜色被卡住了很长时间。看起来在重传期间长度仍在增长。冻结后的这段时间完全是紫色的,所以我怀疑 ESP32 正在处理积压的工作。 docs.google.com/spreadsheets/d/…
    • 我会研究一下 UDP 套接字,看看是否有帮助。
    猜你喜欢
    • 1970-01-01
    • 2020-03-09
    • 2018-12-19
    • 2017-05-19
    • 2021-04-16
    • 2017-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多