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.

[参考译文] AM2732:LwIP UDP 数据损坏

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

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1589001/am2732-lwip-udp-data-corruption

部件号: AM2732

您好专家!
在开发 UDP 客户端时,我们发现了一个奇怪的问题:在连续发送大量数据时,数据包损坏。
我稍微修改了 mcuplus SDK 中的 enet_cpsw_udpclient 示例、复制了这个问题。

最重要的代码片段是在 app_udpclient.c 内部和函数 AppSocket_simpleClient 内部

            CacheP_wbInv(snd_buf, sizeof(snd_buf), CacheP_TYPE_ALLD);
            ret = lwip_sendto(sock, snd_buf, sizeof(snd_buf), 0,
                    pAddr, sizeof(*pAddr));

            // NOTE: THIS FIXES THE PROBLEM
            // ClockP_usleep(10 * 1000);

通过取消对睡眠模式的注释、代码会产生预期的行为、即发送 1024 字节的 UDP 数据包、每个数据包具有交替模式(一次为 0xAA、一次为 0xBB)。
如果我没有睡眠、数据包会损坏、使得模式不再交替每个数据包、而是采用相同模式的数据包链。

附件您可以找到:
-项目来源
- Wireshark 捕获代码而不睡眠
- Wireshark 捕获的代码与睡眠

提前感谢

enet_cpsw_udpclient_am273x-evm_r5fss0-0_freertos_ti-arm-clang.zip

wireshark_captures.zip

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

    尊敬的 
    LwIP 不能很好地支持 LwIP 套接字 API、而是建议使用 LwIP netconn API。  
    是否可以修改应用程序并使用 netconn API 发送 UDP 数据包?

    参考资料: https://lwip.fandom.com/wiki/Application_API_layers

    此致、
    Pradeep

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

    您好 Pradeep HN 
    在尝试修改示例以使用 netconn API 时、我还注意到套接字 API 构建在 netconn + netbuf 之上。
    正如您从 lwip_sendto 的实现中看到的那样:

    ssize_t
    lwip_sendto(int s, const void *data, size_t size, int flags,
                const struct sockaddr *to, socklen_t tolen)
    {
      struct lwip_sock *sock;
      err_t err;
      u16_t short_size;
      u16_t remote_port;
      struct netbuf buf;
    
      sock = get_socket(s);
      if (!sock) {
        return -1;
      }
    
      if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
    #if LWIP_TCP
        done_socket(sock);
        return lwip_send(s, data, size, flags);
    #else /* LWIP_TCP */
        LWIP_UNUSED_ARG(flags);
        set_errno(err_to_errno(ERR_ARG));
        done_socket(sock);
        return -1;
    #endif /* LWIP_TCP */
      }
    
      if (size > LWIP_MIN(0xFFFF, SSIZE_MAX)) {
        /* cannot fit into one datagram (at least for us) */
        set_errno(EMSGSIZE);
        done_socket(sock);
        return -1;
      }
      short_size = (u16_t)size;
      LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
                 (IS_SOCK_ADDR_LEN_VALID(tolen) &&
                  ((to != NULL) && (IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))))),
                 set_errno(err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
      LWIP_UNUSED_ARG(tolen);
    
      /* initialize a buffer */
      buf.p = buf.ptr = NULL;
    #if LWIP_CHECKSUM_ON_COPY
      buf.flags = 0;
    #endif /* LWIP_CHECKSUM_ON_COPY */
      if (to) {
        SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port);
      } else {
        remote_port = 0;
        ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr);
      }
      netbuf_fromport(&buf) = remote_port;
    
    
      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
                                  s, data, short_size, flags));
      ip_addr_debug_print_val(SOCKETS_DEBUG, buf.addr);
      LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
    
      /* make the buffer point to the data that should be sent */
    #if LWIP_NETIF_TX_SINGLE_PBUF
      /* Allocate a new netbuf and copy the data into it. */
      if (netbuf_alloc(&buf, short_size) == NULL) {
        err = ERR_MEM;
      } else {
    #if LWIP_CHECKSUM_ON_COPY
        if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) {
          u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
          netbuf_set_chksum(&buf, chksum);
        } else
    #endif /* LWIP_CHECKSUM_ON_COPY */
        {
          MEMCPY(buf.p->payload, data, short_size);
        }
        err = ERR_OK;
      }
    #else /* LWIP_NETIF_TX_SINGLE_PBUF */
      err = netbuf_ref(&buf, data, short_size);
    #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
      if (err == ERR_OK) {
    #if LWIP_IPV4 && LWIP_IPV6
        /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
        if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) {
          unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr));
          IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4);
        }
    #endif /* LWIP_IPV4 && LWIP_IPV6 */
    
        /* send the data */
        err = netconn_send(sock->conn, &buf);
      }
    
      /* deallocated the buffer */
      netbuf_free(&buf);
    
      set_errno(err_to_errno(err));
      done_socket(sock);
      return (err == ERR_OK ? short_size : -1);
    }


    您能否添加更多详细信息、说明为什么切换到 netconn API 会采取任何措施来解决此问题?  
    谢谢