[2016-04-12已解决,芯片BUG]Lwip RAW模式TCP发送数据阻塞
本帖最后由 xivisi 于 2016-4-12 16:18 编辑2016-04-12:
终于发现问题所在,使用的处理器有缺陷,外置SDRAM居然不允许ARM核和DMA同时访问(仅内置SRAM支持,日了狗了),芯片缺陷手册居然没有对应描述。调整软件构架、精简内存占用,已解决。
2016-04-07:
昨晚继续进行测试,刚刚发现连接断开,经查,PCB出现了死循环:
、==================================================================
2016-04-06:
仅协议栈和协议栈相关层代码的情况下:回环、单发、单收均无问题,一加上同事的应用层代码,就出现之前的问题(我的代码几乎没有任何修改)。目前只能判定,同事的代码有问题;
===========================================================================================================
目前在调一个 LWIP RAW TCP发送代码,单词发送的数据量比较大,目前48KB;
目前故障现象:发送成功一个包之后,发现该pcb的发送缓存一直满,再也不能发送数据,求助
以下是发送函数的代码:
<i>err_t app_net_connect_send(connect_t *connect)
{
err_t result;
connect_txdata_t *txdata;
uint32_t buf_len, ipc_len, tx_send, write_len;
struct tcp_pcb *tpcb;
txdata = connect->tx_work; //获取正在发送的数据块
if(txdata == NULL) //如果没有正在发送的数据
{
//从等待发送的链表中取出一个数据块
txdata = (connect_txdata_t*)list_fifo_remove(&connect->tx_ready);
if(txdata) //如果数据块存在
{
//标记为正在发送的数据块
connect->tx_work = txdata;
//预先放入完成队列,由TCP接收回调函数处理
list_fifo_insert(&connect->tx_finish, &txdata->link);
}
else return ERR_OK;
}
//取出pcb
tpcb = connect->pcb;
assert(tpcb == NULL);
//计算剩余发送数据的长度
ipc_len = txdata->length;
tx_send = txdata->tx_send;
write_len = ipc_len - tx_send;
if(write_len)
{
//使发送数据的长度不超过,TCP发送缓存
buf_len = tcp_sndbuf(tpcb);
if(write_len > buf_len) write_len = buf_len;
//数据加入发送队列
result = tcp_write(tpcb, &txdata->data, write_len, 1);
if(result != ERR_OK) return result;
//强制数据立即发送
tcp_output(connect->pcb);
tx_send += write_len;
}
//如果所有数据已交给协议栈,认为当前数据块已发送完毕
if(tx_send == txdata->length) connect->tx_work= NULL;
//否则只记录发送数据大小
else txdata->tx_send = tx_send;
return ERR_OK;
}</i>
更换老版本lwip1.3.2问题依旧,代码操作问题,或配置不正确的可能性比较大
相关配置如下:
#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__
#define SYS_LIGHTWEIGHT_PROT 0
#define NO_SYS 1
#define NO_SYS_NO_TIMERS 1
#define MEM_ALIGNMENT 4
//#define ETH_PAD_SIZE 2
#define MEM_LIBC_MALLOC 1
#if !MEM_LIBC_MALLOC
#define MEM_USE_POOLS 0
#if MEM_USE_POOLS
#define MEM_USE_POOLS_TRY_BIGGER_POOL 0
#define MEM_USE_CUSTOM_POOLS 0
#define MEMP_USE_CUSTOM_POOLS 0
#define MEMP_SEPARATE_POOLS 0
#else
#define MEM_SIZE (4*1024*1024)
#endif
#endif
#define MEMP_NUM_PBUF 4096
#define MEMP_NUM_UDP_PCB 4
#define MEMP_NUM_SYS_TIMEOUT 300
#define PBUF_POOL_SIZE 512
#define PBUF_POOL_BUFSIZE 1536
#define LWIP_RAW 1
#define LWIP_NETIF_HOSTNAME 1
#define LWIP_BROADCAST_PING 1
#define LWIP_TCP 1
#define MEMP_NUM_TCP_PCB 32
#define MEMP_NUM_TCP_PCB_LISTEN 2
#define MEMP_NUM_TCP_SEG (TCP_SND_QUEUELEN+64)
#define TCP_TTL 255
#define TCP_QUEUE_OOSEQ 0
#define TCP_MSS (1460)
#define TCP_SND_BUF (8*TCP_MSS)
#define TCP_SND_QUEUELEN ((16*(TCP_SND_BUF)+(TCP_MSS-1))/(TCP_MSS))
#define LWIP_ICMP 1
#define LWIP_DHCP 0
#define LWIP_UDP 1
#define UDP_TTL 255
#define LWIP_SOCKET 0
#define LWIP_NETCONN 0
#define LWIP_STATS 0
#define LINK_STATS 0
#define LWIP_STATS_DISPLAY 0
#define LWIP_PROVIDE_ERRNO 1
#define LWIP_NETIF_LINK_CALLBACK 0
#define LWIP_NETCONN 0
#define LWIP_SOCKET 0
#include <stdlib.h>
#define LWIP_DEBUG 0
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
#endif /* __LWIPOPTS_H__ */ 自己顶 回环模式:接收时拷贝到接收队列,在大循环中调用楼主位发送函数;测试发送 600K的文件,无问题;
但是取消回环模式,加上应用代码(确认应用数据已加入发送队列),立马歇菜。 更改回环模式:只要接收到任意数据,则持续不断向外每次发送100K数据(相对于发送缓冲,对应于connect->tx_ready这个fifo队列),测试无问题…… 不用tcp_output试试,因为raw模式下延时到了自己会发送数据,而tcp_output很可能在协议栈的回调函数里操作协议栈的流程,我认为很可能就会破坏协议的完整性 myxiaonia 发表于 2016-3-29 14:04
不用tcp_output试试,因为raw模式下延时到了自己会发送数据,而tcp_output很可能在协议栈的回调函数里操作 ...
我不是在回调函数里面调用 tcp_output 本帖最后由 xivisi 于 2016-3-29 14:30 编辑
抓包,传输终止的地方,没看出异常……
LWIP:192.168.1.115
PC : 192.168.1.107
修改发送缓冲大小、增大对应的pbuf数量,目前不阻塞于发送函数tcp_write;
但是,在发送完成函数中(由tcp_sent指定的回调函数),并没有收到对应数量的应答。LWIP 未收到ACK响应? xivisi 发表于 2016-3-29 14:10
我不是在回调函数里面调用 tcp_output
你以上所发的函数不是发送回调函数吗 这个函数是在什么情况下调用的 本帖最后由 xivisi 于 2016-3-29 15:36 编辑
myxiaonia 发表于 2016-3-29 15:31
你以上所发的函数不是发送回调函数吗 这个函数是在什么情况下调用的
发送回调函数是由tcp_sent(pcb, app_net_connect_sent);设置的,我的
回调函数是:app_net_connect_sent;
发送函数是:app_net_connect_send,这个很明显是其他任务产生的数据进,在大循环了调用(与 sys_check_timeouts() 平齐);
err_t app_net_connect_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
uint32_t tx_sent;
connect_t *connect;
connect_txdata_t *txdata;
error_t result;
connect = (struct connect_t *)arg;
assert(connect == NULL);
txdata = (connect_txdata_t*)list_fifo_get_first(&connect->tx_finish);
assert(txdata == NULL);
tx_sent = txdata->tx_sent;
tx_sent += len;
while(tx_sent >= txdata->length)
{
result = app_ipc_net_tx_finish(connect->id, txdata->data, txdata->length, tx_sent);
if(result == ERR_NORMAL)
{
list_fifo_remove(&connect->tx_finish);
list_single_insert_first(&net.list_free, &txdata->link);
}
tx_sent -= txdata->length;
txdata = (connect_txdata_t*)list_fifo_get_first(&connect->tx_finish);
}
if(txdata) txdata->tx_sent = tx_sent;
return ERR_OK;
}
app_net_connect_sent只有list操作吗我没有看到真实的发送操作
一般lwip的raw流程,都是要在lwip协议里通过回调函数的形式操作的,你可以看看rtt的lwip的netio程序,那里就是完全的此类做法 本帖最后由 xivisi 于 2016-3-29 16:09 编辑
myxiaonia 发表于 2016-3-29 15:44
app_net_connect_sent只有list操作吗我没有看到真实的发送操作
一般lwip的raw流程,都是要在lwip协议里 ...
如果像你说的那样,那发送数据的回调函数怎么触发???
操作队列的目的是,保证发送的数据被对方接收到之后,释放对应的内存。 本帖最后由 xivisi 于 2016-3-30 10:47 编辑
myxiaonia 发表于 2016-3-29 15:44
app_net_connect_sent只有list操作吗我没有看到真实的发送操作
一般lwip的raw流程,都是要在lwip协议里 ...
死马当活马医,更改了操作模式,依然有些问题;
并且速度暴降到原来的1/10 本帖最后由 xivisi 于 2016-3-30 12:34 编辑
抓取到一个错误,但是可恢复:
xivisi 发表于 2016-3-29 16:06
如果像你说的那样,那发送数据的回调函数怎么触发???
操作队列的目的是,保证发送的数据被对方接收到 ...
lwip有个帮助文件,rawapi.txt 貌似是这个
发送回调函数什么时候调用,那里有讲解,一般会在发送缓冲区有空的时候,也就是收到对方确认应答后自动回调
也可以调用tcp_write发送,不过要保证协议完整性,协议栈的函数基本上都是不可重入的你得有这个前提
裸机模式下在中断中调用就必须小心,带os的话通过api把此函数调用推入到lwip线程执行 本帖最后由 xivisi 于 2016-3-30 13:21 编辑
myxiaonia 发表于 2016-3-30 13:10
lwip有个帮助文件,rawapi.txt 貌似是这个
发送回调函数什么时候调用,那里有讲解,一般会在发送缓冲区 ...
4楼已说明,在主程序大循环调用。
对于接收数据也是在大循环里调用,没有使用任何中断,没有使用操作系统。
回调函数仅处理已发送数据,这样实现异步逻辑,加快发送速度。非回调函数调用 tcp_write 需要调用tcp_output实现立即发送。 调整配置选项,TCP层无用。后来找默认配置里面,IP层发送相关配置,成功。昨晚跑了一晚上OK! 问题,又出现了。。。。。。。 抓到BUG一只 已解决 请问是什么BUG,如何解决,我也遇到了和你一样的现象
页:
[1]