This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] RTOS:TI-RTOS NDK 中的 TCP 数据包丢失

Guru**** 2618835 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/574463/rtos-tcp-packet-loss-in-ti-rtos-ndk

工具/软件:TI-RTOS

您好!

我正在使用连接到无线路由器的 TM4C129EXL 器件。 我与网络上的其他端点进行基于 TCP 协议的通信。 TM4C129充当 TCP 套接字服务器、我有一个 Android TCP 客户端。 建立连接后、客户端使用阻塞套接字读取方法等待来自 UC 的数据包、这是单向通信。 (它是一种数据采集系统。) 我从 UC 端发送的每个数据包都有一个计数器值、我在每次发送时都会递增。 如果是 delta btw、客户端将收到有关数据包丢失的通知。 每个计数器大于1。

我的情况如下:当多个无线 AP 在同一房间中时(WiFi 频道可能相同->可能拥塞)、我会看到大量数据丢失。 TCP 是一种可靠的协议、因此不会丢失任何数据包。 因此,当发送方未收到 SENS()的 ACK 时,应开始重新传输。

我的问题如下。 如果连续发送数据包的 UC 发生重新传输、需要重新传输的数据存储在何处? API 是否会覆盖它?

我在 uC 侧生成一个三角形信号、在接收器侧、我的信号有一些变形。 有些数据包丢失了 I、但使用寿命会延长、并且会接收到更多数据包。 丢失的数据包会怎么样? UC 尝试重新传输数据包的次数是多少? 在最后一次重新传输失败后、如果其他数据包交付良好、会发生什么情况? 是否有任何方法来检测此事件? 在客户端、我没有任何例外...

期待您的回复。

P.S.:您能否推荐任何 TI 文档、以便我获得有关 NDK TCP 数据包丢失的更多详细信息?  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Daniel:

    很抱歉耽误你的时间。 我正在联系开发团队回答您的问题。

    ~Ramsey

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    好的。 如果出现新情况、请告诉我。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Daniel:

    我收到了以下信息。

    NDK 收集一些可能对您有所帮助的统计信息。 有一个名为 TCPS 的全局变量、其中包含有关数据包丢失和重新传输的信息。 停止 CCS。 在观察窗口中输入变量名称以查看数据。

    [引用用户="Daniel Vamos"]

    我的问题如下。 如果连续发送数据包的 UC 发生重新传输、需要重新传输的数据存储在何处? API 是否会覆盖它?

    [/报价]

    准备发送的数据存储在 TCP 发送缓冲区中。 该缓冲区是调用 send()的 TCP 套接字的 TX 套接字缓冲区。 TCP 会将数据保留在缓冲区中、直到收到 ACK。

    如果您需要更多信息、请告诉我。

    ~Ramsey

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    在上一篇文章中、以下链接与我共享:  

    哪一个是对丢失的数据包进行计数?  

    如果我错了、请更正我:

    发送方将 TCP 数据包发送到目的方。 如果 ACK 未应答、则尝试重新发送同一数据包。 此时没有其它数据包发送,发送方正在尝试将数据包发送到目的。 如果失败、则连接断开。 是这样吗? 您是否有一些我需要学习的 NDK 特定文档?

    NDK 中的重新传输数量是多少? 我可以更改它吗? 当我们说 TCP 数据包被丢弃时? 那么、TCP 的可靠性呢?  

    在我的情况下、发送方通过以太网将数据包传输到路由器、而数据包通过 Wifi 进行转发。 有些数据包未到达、但连接仍处于活动状态、接下来的数据包将发送。 在这种情况下、我的支持是错误的、因为连接应该被关闭。  

    感谢你的帮助、

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Daniel、您好!

    [引用 user="Daniel Vamos"] NDK 中的重传次数是多少? 我可以更改它吗? 当我们说 TCP 数据包被丢弃时? 那么、TCP 的可靠性呢?  [/报价]

    您可以在以下数组中看到重新传输时间。  堆栈是开源的、因此您可以自由地修改这些值并重建/重新运行应用程序:

    tcptime.c
    
    /* tcp_backoff -应用于计时器节拍的指数退避*/
    静态 uint32 tcp_backoff[tcp_MAXBUFF+1]=
    {1、2、4、8、16、 32、64、64、64、128、 128、128、128}; 

    您可以看到重新传输是如何工作的 TcpTimeoutRexmt()。

    在 TCP 中、每次发送数据包时都会设置计时器。  如果在计时器到期之前没有 RX、TCP 会尝试重新传输。  它会再次设置计时器、但这次超时值会增加(回退)、以允许另一侧有更多的响应时间。  这种情况会重复、直到最终接收到数据包或达到/尝试最大回退时间。

    您还可以在代码中看到、在最后一次尝试重新传输后、连接中断。

    [引用 user="Daniel Vamos"]嗯、哪一个正在计算丢失的数据包?  [/报价]

    这些统计数据应帮助您了解有关上述情况的更多信息:

    TCPS.RexmtTimeout++;//当重发送计时器过期时,此值会递增。  这意味着数据包被重新传输、ACK 不会及时 RX

    TCPS.TimeoutDrops++;//堆栈尝试重新发送最大次数但最终失败-从未接收到 ACK 后,这将增加

    Steve

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的 Steve:

    感谢您的回答、但我有最后一个问题。

    从 UC 端、我将生成 TCP 数据包、并以大约4Hz 的频率将其发送到客户端。 如果出现网络问题(拥塞等) 在250ms 内无法将数据包传输到客户端(但是 TCP 会反复尝试重新传输数据包)。 如果 uC 在250ms 后生成新数据包、那么前一个数据包是否会丢失? 我是说、旧的未传输数据包会被 UC 生成的新数据包覆盖?

    感谢你的答复。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Daniel:

    TCP 是可靠的,因此它必须保留一个您在要发送的呼叫中传递的数据的副本(),直到另一方收到 ACK。  请注意,send()返回并不意味着数据已发送,只是成功地将数据传递给 TCP 协议层[假设从 send()成功返回]。  根据拥塞和/或窗口大小、数据可能会在实际传输之前被 TCP 协议延迟。

    如果我们从未收到 ACK、则连接会中断(在我的上一篇文章中介绍)。

    [引用 user="Daniel Vamos"]如果 UC 在250ms 后生成新数据包,是否可以丢失前一个数据包? 我是说、旧的未传输数据包会被 UC 生成的新数据包覆盖? [/报价]

    简而言之,答案是否定的

    我想你在这里的意思是,如果你再次调用 send(),并且之前调用 send()中的数据仍然被保留在套接字缓冲区中,因为它尚未被 ACK。

    在这种情况下,如果套接字缓冲区中有空间,您的(第二个)发送呼叫的数据将被复制到套接字缓冲区,SEND ()将返回成功。

    *如果套接字缓冲区中没有空间,则在套接字缓冲区中的更多数据可用之前(即,直到收到以前发送的数据的 ACK),发送()的调用将被阻止。  它不会覆盖套接字缓冲区中的现有数据。  空间可用后,数据将被写入套接字缓冲区,SEND ()将返回成功(成功写入的字节数)。

    *-->请注意,只有当您的套接字阻塞时,才会出现这种情况。  如果您的套接字是非阻塞式的、则它不能等待套接字缓冲区中的空间变为可用状态、因此在这种情况下、SEND 将返回故障(-1、errno 设置为 EWOULDBLOCK)。

    最后、即使您的套接字处于阻塞状态、它也只能在有限的时间内阻塞。  如果在到达套接字块超时之前空间不可用、那么 SENSE()也将返回 EWOULDBLOCK 的-1和 errno。

    Steve

    编辑:修复了几个小错误

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    非常感谢您提供始终如一的详细答案。 嗯、我不知道我的数据在哪里、因为在接收器侧、我在接收器侧有一些缺失的数据包...
    现在、我们有了解决此问题的权变措施、我99%地确定问题不在 UC 端。
    我可以接受您的回复作为答案、但在几天或几周后、我可能会在收集有关问题的更多信息时打开一个新主题。

    谢谢你
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    没问题。 我建议使用 Wireshark 或 tcpdump 来捕获线路上发生的情况。

    由于从 UC 到路由器的连接是有线连接、因此您应该能够使用具有端口镜像的智能交换机(例如、在 UC 和路由器之间放置交换机、 然后将 UC 连接到的端口镜像到交换机上的另一个端口。 然后将运行 Wireshark 的 PC 连接到此镜像端口并运行捕获)。

    或者、如果您的路由器运行 Linux、您可以登录到它并运行 tcpdump 以查看从 UC 进入路由器的所有流量。

    如果您在捕获中看到从 UC 发送的所有数据、那么您肯定知道 NDK 正在完成其工作、您可以从可能的罪犯列表中删除 UC。

    能够看到线缆上发生的情况将极大地帮助您确定问题。

    Steve
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    很棒的想法! 感谢你的帮助!

    Relaxedμ A

    如果我检测到任何与 NDK 相关的问题、我会告知您!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    今天,拉姆西和我仍在简短地讨论这一问题,并考虑了其他一些问题。


    在调用 send()时,是否检查发送的字节数是否等于要发送的字节数? [即 send()的返回值]


    例如,如果要发送50个字节,是否检查 send()返回了50个字节?

    Steve

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    感谢您的更新。 以下是我的 TX 代码:

    //start = Timestamp_get32 ();
    //
    将数据包发送到客户端。 如果删除了客户端,中断将关闭任务和
    //关闭套接字
    //
    if (send (socket、txPacket、sm_tcp_packet_size_RAMREADER、0)!= sm_tcp_packet_size_RAMREADER){
    NOP();
    //中断循环
    ;
    } 

    我将举一个超级简单的例子来演示这种情况。 由于我必须完成的任务不受限制、我需要花几天时间才能完成。 )

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Daniel:

    是否可以尝试更改上述代码以确保 send()写入预期要写入的所有字节?

    对其进行或多或少的更改、如可以在此处看到的"send_all()"函数:

    http://stackoverflow.com/questions/2618736/why-is-it-assumed-that-send-may-return-with-less-than-requested-data-transmitted

    [引用 user="Daniel Vamos"] if (send (socket、txPacket、sm_tcp_packet_size_RAMREADER、0)!= sm_tcp_packet_size_RAMREADER){NOP();//中断循环中断;}

    我想您可能会遇到这样的情况:套接字缓冲区没有足够的空间容纳 SM_tcp_packet_size_RAMREADER 字节(但它有空间容纳少于此字节的某些字节)。


    在这种情况下,上面对 send()的调用将返回成功(即,它能够成功写入的字节数是多少),但上面的代码将其视为失败情况,因为 if 语句对此进行了管理。

    您还可以通过打印出该 if 语句中实际接收的字节数来检查您是否曾在故障情况下遇到过此问题。  但是,由于重新生成需要很长时间,也许您应该尝试 send_all()更改并添加一个打印输出,以便让您知道 send()是否返回的字节数小于预期的字节数。

    Steve

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    感谢您的建议。 正如您所说、我将在周一组织一次测试会议。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    想知道您是否有机会尝试一下吗?

    Steve