BUG: udp的"addrlen"由局部变量改为全局变量,udp的数据包就无法发送到目标地址。

一.BUG描述

项目上要用到LWIP的UDP协议传输数据,然后弄了一个了UDP的demo;跑通了之后就对这个demo重新封装。我把套接字长度变量(addrlen)由局部改为全局之后,服务器的UDP就只能接收,不能发送数据了。


二.BUG原因

点击查看代码
/*
*sockfd:套接字文件描述符
*buf:接收缓冲区
*len:接收数据长度
*flags:标识
*src_addr:对端套接字地址
*addrlen:对端套接字地址长度,也就是src_addr这个结构体的大小,IPV4网络为16个字节
*/
int  lwip_recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)

1.全局变量存储在BSS段,若全局变量没有初始化赋值,则默认为0值;而局部变量保存在栈种,若没有初始化赋值,则局部变量为随机值。
2.在recvfrom()函数中,若addrlen的初始化值大于对端的地址长度;则会被重置为16个字节,若小于对端的地址长度,则直接读对端的地址信息,导致对端地址信息不全,也就无法发送。代码如下:

点击查看代码
int lwip_recvfrom(int s, void *mem, size_t len, int flags,struct sockaddr *from, socklen_t *fromlen)
{
    ...
    ...
    /* Check to see from where the data was.*/
    if (done) {
      ip_addr_t fromaddr;
      if (from && fromlen) {
        struct sockaddr_in sin;

        if (netconn_type(sock->conn) == NETCONN_TCP) {
          addr = &fromaddr;
          netconn_getaddr(sock->conn, addr, &port, 0);
        } else {
          addr = netbuf_fromaddr((struct netbuf *)buf);
          port = netbuf_fromport((struct netbuf *)buf);
        }

        memset(&sin, 0, sizeof(sin));
        sin.sin_len = sizeof(sin);
        sin.sin_family = AF_INET;
        sin.sin_port = htons(port);
        inet_addr_from_ipaddr(&sin.sin_addr, addr);

        if (*fromlen > sizeof(sin)) {      //sizeof(sin)是ipv4套接字地址的长度
          *fromlen = sizeof(sin);
        }

        MEMCPY(from, &sin, *fromlen);      //拷贝对端地址到本地。

        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
        ip_addr_debug_print(SOCKETS_DEBUG, addr);
        LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
      } else {
#if SOCKETS_DEBUG
        if (netconn_type(sock->conn) == NETCONN_TCP) {
          addr = &fromaddr;
          netconn_getaddr(sock->conn, addr, &port, 0);
        } else {
          addr = netbuf_fromaddr((struct netbuf *)buf);
          port = netbuf_fromport((struct netbuf *)buf);
        }

        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
        ip_addr_debug_print(SOCKETS_DEBUG, addr);
        LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
#endif /*  SOCKETS_DEBUG */
      }
    }

    
  ...
  ...


三.解决办法

因采用IPv4网络进行通信,它的套接字地址长度就是16,所以初始化的时候令addrlen = 16即可。

点击查看代码
static struct udp_net_socket udp_socket = {
    .sock = -1,
    .seraddr = 0,
    .addrlen = sizeof(struct sockaddr_in),
};
posted @ 2024-11-19 14:44  Charles_hui  阅读(3)  评论(0编辑  收藏  举报