lwIP TCP栈:消息超缓冲区时tcp_recved调用及pbuf相关疑问
lwIP tcp_recved 相关问题解答
我正在树莓派Pico上用C语言开发小型TCP项目,基于lwIP API开展实验,参考资料包含pico-sdk-examples。lwIP栈收到消息时会调用开发者指定的回调方法,示例中该方法通过pbuf结构体处理消息(可通过pbuf链处理长消息),核心代码如下:
//state是协议控制结构体 //p是pbuf结构体 // 接收缓冲区 const uint16_t buffer_left = BUF_SIZE - state->recv_len; state->recv_len += pbuf_copy_partial(p, state->buffer_recv + state->recv_len, p->tot_len > buffer_left ? buffer_left : p->tot_len, 0); tcp_recved(tpcb, p->tot_len);
疑问与解答
1. 若p->tot_len大于缓冲区大小且缓冲区已填满,示例代码为何仍传入p->tot_len调用tcp_recved?超出缓冲区的数据会丢失吗?
这是示例代码的错误写法。tcp_recved的作用是告知lwIP栈:应用已经处理了指定字节数的数据,栈可以释放对应pbuf内存并更新TCP窗口。如果只拷贝了buffer_left字节到应用缓冲区,却传入p->tot_len调用tcp_recved,lwIP会误以为所有数据都被处理,直接释放整个pbuf链的内存,超出缓冲区的那部分数据就会永久丢失。
正确的做法是传入实际拷贝的字节数(即buffer_left),这样lwIP会保留未处理的pbuf数据,等待下一次回调时应用继续读取。
2. 为何不使用p->len?
p->len是当前单个pbuf节点的长度,而p->tot_len是整个pbuf链的总长度。lwIP会把一段TCP数据拆分成多个pbuf节点组成链来存储,所以必须用p->tot_len才能获取本次收到的全部数据长度。如果用p->len,只能处理当前节点的数据,会漏掉链中其他节点的内容,导致数据不完整。
3. 使用lwIP TCP栈时,接收消息大于缓冲区会发生什么?
- 如果像示例那样错误处理:调用tcp_recved传入全部数据长度,超出缓冲区的部分会直接丢失,且无法恢复。
- 如果正确处理:只调用tcp_recved传入实际处理的字节数,lwIP会将未处理的pbuf数据保留在TCP接收队列中,不会向发送方发送这部分数据的ACK。此时发送方因为未收到ACK,会触发重传或者停止发送(直到窗口更新)。等应用缓冲区有空闲空间后,可在回调中继续读取剩余数据,再调用tcp_recved告知栈已处理,更新TCP窗口,发送方就能继续发送后续数据。
内容的提问来源于stack exchange,提问作者Thomas Stokes
相关产品推荐
相关产品推荐

