2012-06-18 53 views
8

我正在使用名为lwip的TCP/IP堆栈。我已经在下面实现了一个函数来发送数据包,这得益于类似的接收数据包的回调函数。LightWeight IP:缓冲区未释放

每次收到数据包时,我都会使用pbuf_alloc函数创建一个缓冲区。然后,我使用udp_sendto发送数据包。最后,我使用pbuf_free释放缓冲区。 (请参阅下面的代码。)

由于某些原因,pbuf_free未释放缓冲区。 (我拿到后n个包,其中n是池大小缓冲区溢出。)The lwip wiki警告说:

网络驱动程序也可以不承担时,它调用pbuf_free该PBUF内存 实际上释放。

如何强制pbuf_free释放我的缓冲区?如何避免缓冲区溢出?

(我下面执行)

static err_t IAP_tftp_send_data_packet(struct udp_pcb *upcb, struct ip_addr *to, int to_port, int block) 
{ 
    err_t err; 
    struct pbuf *pkt_buf; 
    char packet[TFTP_DATA_PKT_LEN_MAX]; 
    int bytesRead; 
    int bytesToSend; 

    /* Specify that we are sending data. */ 
    IAP_tftp_set_opcode(packet, TFTP_DATA); 

    /* Specify the block number that we are sending. */ 
    IAP_tftp_set_block(packet, block); 

    bytesRead = IAP_tftp_set_data(packet, block); 

    if(bytesRead != 0) { 
    bytesToSend = TFTP_DATA_PKT_LEN_MAX - (512 - bytesRead + 1); 
    } else { 
    bytesToSend = TFTP_DATA_PKT_LEN_MAX - 512; 
    } 

    pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_POOL); 

    if (!pkt_buf) 
    { 
    print("(TFTP) Buffer overflow!\r\n"); 
    } 

    /* Copy the file data onto pkt_buf. */ 
    memcpy(pkt_buf->payload, packet, bytesToSend); 

    err = udp_sendto(upcb, pkt_buf, to, to_port); 

    /* free the buffer pbuf */ 
    printf("%d\n\r", pbuf_free(pkt_buf)); 

    return err; 
} 
+0

您是否检查缓冲区的引用计数?恐怕只有引用计数为1时才会释放它。 – Fred

+0

可能'udp_sendto'接受一个引用并以异步方式释放它(在一个定时器中?)。也许你只需要给它一段时间? – ugoren

+0

@ugoren:我尝试了等待,虽然有缓冲区溢出,但缓冲区溢出仍然存在。 – Randomblue

回答

7

您使用的是什么版本的lwIP? 根据不同的版本,答案差异很大。

在pbuf_alloc()中调用的memp_malloc()分配函数失败或者pbufs链接失败。所以它返回NULL。

如果传递的参数也包含NULL(由于NULL参数检查),pbuf_alloc()也会返回NULL。

在较新的版本中,您能否显示MEMP_OVERFLOW_CHECK宏包含的值?当宏值> = 2时,lwIP显示出不同的行为。

而另一个原因可能是如果使用多线程,pbuf_alloc()失败的锁定机制可能会导致它返回NULL。

某些版本要求您在调用pbuf_alloc()之前调用pbuf_init()。

你可以试试这个:

pkt_buf = NULL;//Use NULL, just incase the NULL is not 0 as per your compiler. 
pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_REF); 
if(pkt_buf == NULL) 
{ 
    printf("pbuf_alloc failed.\n"); 
} 
else 
{ 
    /* Do something with the allocated pbufs and free it. */ 
} 

PBUF_REF将分配没有缓冲存储器的pbuf。 pbuf只能在单个线程中使用,如果pbuf排队,则应调用pbuf_take来复制缓冲区。

您也可以尝试PBUF_RAM,它将在RAM中分配缓冲区。

有关更多信息,还可以浏览正在使用的lwIP版本的源文件。

+0

让我知道如果这个答案仍然没有回答你的问题。 – askmish

+0

我给你赏金,因为你的答案是最有前途的。在我有时间调查时,我可能不得不问你更多的细节。谢谢。 – Randomblue

+0

如果您感觉舒适且有足够的时间,我会建议您阅读您的版本的源代码,而不是维基。 wiki维护得不好。 – askmish

6

最简单的解决方案似乎是使缓冲static,即再利用每个呼叫同一缓冲区:

static struct pbuf *pkt_buf = NULL; 

if(pkt_buf == NULL) 
    pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_POOL); 
if(pkt_buf == NULL) 
{ 
    print("(TFTP) Buffer overflow!\r\n"); 
} 

如果您的方案涉及卸载/重新加载驱动程序,它会泄漏内存。要解决这个问题,请将缓冲区设置为IAP_tftp_send_data_packet()函数的外部,并在驱动程序卸载(假设lwip告诉您)时调用pbuf_free()

+0

嗡嗡声,不起作用。好主意,但。 – Randomblue

0

只是一个过去的想法,可能完全荒谬。在此代码:

if(bytesRead != 0) { 
    bytesToSend = TFTP_DATA_PKT_LEN_MAX - (512 - bytesRead + 1); 
} else { 
    bytesToSend = TFTP_DATA_PKT_LEN_MAX - 512; 
} 
pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_POOL); 

...有可能是bytesRead承担了价值513 - TFTP_DATA_PKT_LEN_MAX?

如果发生了,分配零字节的请求不会失败吗? (这可以通过在缓冲区溢出时打印bytesToSend的值并检查它是否为非零来测试)。

0

struct pbuf不代表连续的内存区域。它相当于一连串的记忆位置。因此,这在一般情况下不起作用:

memcpy(pkt_buf->payload, packet, bytesToSend); 

您需要分散复制您的数据。来自代码片段的memcpy()可能会溢出有效载荷缓冲区,并导致各种副作用,包括无法完全释放p​​buf链。