java(或python)服务器有时未收到 TCP 数据

TCP data sometimes not received by java (or python) server

我正在开发一个由 arduino mkr1000 组成的系统,我想通过 wifi 将数据发送到本地网络中的 java 服务器程序 运行。

除主要部分外一切正常:服务器有时未收到 arduino 发送的数据...

我正在使用 arduino Wifi101 library 连接到我的 wifi,获取 WiFiClient 并发送数据。 以下代码只是演示问题的示例:

for (int i = 0; i < 3; ++i) {
    Serial.println(F("Connecting to wifi"));
    const auto status = WiFi.begin("...", "...");
    if (status != WL_CONNECTED) {
        Serial.print(F("Could not connect to WiFi: "));

        switch (status) {
            case WL_CONNECT_FAILED:
                Serial.println(F("WL_CONNECT_FAILED"));
                break;
            case WL_DISCONNECTED:
                Serial.println(F("WL_DISCONNECTED"));
                break;
            default:
                Serial.print(F("Code "));
                Serial.println(status, DEC);
                break;
        }
    } else {
        Serial.println(F("WiFi status: WL_CONNECTED"));

        WiFiClient client;
        if (client.connect("192.168.0.102", 1234)) {
            delay(500);
            client.print(F("Test "));
            client.println(i, DEC);
            client.flush();

            Serial.println(F("Data written"));

            delay(5000);
            client.stop();
        } else {
            Serial.println(F("Could not connect"));
        }

        WiFi.end();
    }

    delay(2000);
}

java 服务器基于 Netty,但手动创建和读取 Socket 的结果相同。 测试代码非常标准,只有一个简单的输出(注意:在 Kotlin 中):

val bossGroup = NioEventLoopGroup(1)
val workerGroup = NioEventLoopGroup(6)

val serverFuture = ServerBootstrap().run {
    group(bossGroup, workerGroup)
    channel(NioServerSocketChannel::class.java)
    childHandler(object : ChannelInitializer<NioSocketChannel>() {
        override fun initChannel(ch: NioSocketChannel) {
            ch.pipeline()
                    .addLast(LineBasedFrameDecoder(Int.MAX_VALUE))
                    .addLast(StringDecoder())
                    .addLast(object : ChannelInboundHandlerAdapter() {
                        override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {
                            println("msg = $msg")

                            ctx.close()
                        }
                    })
        }
    })

    bind(port).sync()
}

arduino 表明一切正常(即每次迭代都将 Data written 写入串行控制台)但服务器有时会跳过个别消息。 在这些情况下,从 Netty 添加 LoggingHandler 告诉我:

11:28:48.576 [nioEventLoopGroup-3-1] WARN  i.n.handler.logging.LoggingHandler - [id: 0x9991c251, L:/192.168.0.20:1234 - R:/192.168.0.105:63845] REGISTERED
11:28:48.577 [nioEventLoopGroup-3-1] WARN  i.n.handler.logging.LoggingHandler - [id: 0x9991c251, L:/192.168.0.20:1234 - R:/192.168.0.105:63845] ACTIVE

在收到消息的情况下,它告诉我:

11:30:01.392 [nioEventLoopGroup-3-6] WARN  i.n.handler.logging.LoggingHandler - [id: 0xd51b7bc3, L:/192.168.0.20:1234 - R:/192.168.0.105:59927] REGISTERED
11:30:01.394 [nioEventLoopGroup-3-6] WARN  i.n.handler.logging.LoggingHandler - [id: 0xd51b7bc3, L:/192.168.0.20:1234 - R:/192.168.0.105:59927] ACTIVE
11:30:01.439 [nioEventLoopGroup-3-6] WARN  i.n.handler.logging.LoggingHandler - [id: 0xd51b7bc3, L:/192.168.0.20:1234 - R:/192.168.0.105:59927] READ: 8B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 54 65 73 74 20 32 0d 0a                         |Test 2..        |
+--------+-------------------------------------------------+----------------+
11:30:01.449 [nioEventLoopGroup-3-6] WARN  i.n.handler.logging.LoggingHandler - [id: 0xd51b7bc3, L:/192.168.0.20:1234 - R:/192.168.0.105:59927] CLOSE
11:30:01.451 [nioEventLoopGroup-3-6] WARN  i.n.handler.logging.LoggingHandler - [id: 0xd51b7bc3, L:/192.168.0.20:1234 ! R:/192.168.0.105:59927] READ COMPLETE
11:30:01.453 [nioEventLoopGroup-3-6] WARN  i.n.handler.logging.LoggingHandler - [id: 0xd51b7bc3, L:/192.168.0.20:1234 ! R:/192.168.0.105:59927] INACTIVE
11:30:01.464 [nioEventLoopGroup-3-6] WARN  i.n.handler.logging.LoggingHandler - [id: 0xd51b7bc3, L:/192.168.0.20:1234 ! R:/192.168.0.105:59927] UNREGISTERED

根据我的理解,这意味着确实收到了 TCP 数据包,但在错误情况下,来自 Netty 的 IO 线程正在等待读取 TCP 数据,但永远不会继续... 尝试使用基本的 python 服务器(只是等待连接并打印接收到的数据)时存在同样的问题。

我确认数据是通过在 Arch Linux 上使用 tcpflow 和参数 -i any -C -g port 1234 发送的。 我什至在 Windows 7 机器上尝试了服务器,结果相同(用 SmartSniff 确认的 TCP 数据包)。

奇怪的是,使用 java 服务器发送的数据始终可重复接收...

有没有人知道解决问题或至少如何诊断?

PS:也许重要的是要注意 tcpflow(即 linux)我可以看到 TCP 数据包被重新发送到服务器。 这是否意味着服务器正在接收数据包但不发送 ACK? SmartSniff 没有显示相同的行为(但也许我使用了错误的选项来显示重新发送的数据包)。

与此同时,我发送消息以确认收到另一条消息。如果未收到确认,则再次发送消息。


遇到同样问题的人:

在测试不同的东西时,我将电路板的 wifi 固件更新到最新版本 19.5.2。从那以后,我没有注意到任何丢失的数据。也许这就是问题所在。 参见 Check WiFi101 Firmware Version and Firmware and certificates Updater注意: 我无法使用 Arduino IDE 将草图绘制到 运行,但使用 PlatformIO