新手入门
积分 18
金钱 18
注册时间 2018-8-27
在线时间 2 小时
1 金钱
本帖最后由 zhanglang 于 2018-8-28 00:41 编辑
一、硬件环境说明
采用STM32F407ZET6裸跑LWIP,使用CUBEMX生成相关配置
二、项目说明
这是一个串口与网络透传的项目,实现接受串口数据,转发到指定的IP地址。希望能达到,单包传输2K的数据量。
三、问题描述
问题1:MCU发送大量数据到指定IP地址时,出现了数据丢失
问题详细说明:
采用tcp_write()函数发送数据时,发送1K左右的数据量,没有问题,但是当数据量达到2K时候,偶尔会发生数据丢失。
通过串口调试打印得知,在大数据量发送时,tcp_write()函数,产生 ERR_MEM 错误,导致部分数据没有发送成功,使用CubeMX多次尝试重新配置各个可能的参数,问题还是没有得到解决。由于打开 LWIP Debug 选项,在发送2K数据量出现数据丢失时,LWIP同时输出此调试信息。
mem_malloc: could not allocate 1472 bytes
tcp_write : could not allocate memory for pbuf copy size 856
发送部分代码:
[mw_shl_code=cpp,true]void tcp_server_senddata(struct tcp_pcb *tpcb, struct tcp_server_struct *es)
{
struct pbuf *ptr;
u16 plen;
err_t wr_err = ERR_OK;
while ((wr_err == ERR_OK) && (es->p) && (es->p->len <= tcp_sndbuf(tpcb)))
{
printf("tcp_sndbuf=%d es->p->len=%d\r\n", tcp_sndbuf(tpcb), es->p->len);
ptr = es->p;
wr_err = tcp_write(tpcb, ptr->payload, ptr->len, 1);
printf("wr_err=%d\r\n", wr_err);
if (wr_err == ERR_OK)
{
printf("wr_err==ok\r\n");
plen = ptr->len;
es->p = ptr->next;
if (es->p)
pbuf_ref(es->p);
pbuf_free(ptr);
tcp_recved(tpcb, plen);
}
else if (wr_err == ERR_MEM)
es->p = ptr;
tcp_output(tpcb);
}
// tcp_output(tpcb);
}[/mw_shl_code]
问题2:在接收数据时,超过1400Byte将丢失
问题详细说明:
经过排查,是由于 TCP_MSS (Maximum Segment Size) 设置为1400所以超过的数据将丢失,我的目标是实现单包传输2KB数据量,但是这个参数最大只能设置为1400。其他可能的参数也尝试配置过,但是还是没有解决问题!
接受部分代码:
[mw_shl_code=cpp,true]err_t tcp_t4_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
err_t ret_err;
u32 data_len = 0;
struct pbuf *q;
struct tcp_server_struct *es;
LWIP_ASSERT("arg != NULL", arg != NULL);
es = (struct tcp_server_struct *) arg;
if (p == NULL) //从客户端接收到空数据
{
es->state = ES_TCPSERVER_CLOSING; //需要关闭TCP 连接了
es->p = p;
ret_err = ERR_OK;
}
else if (err != ERR_OK) //从客户端接收到一个非空数据,但是由于某种原因err!=ERR_OK
{
if (p)
pbuf_free(p); //释放接收pbuf
ret_err = err;
}
else if (es->state == ES_TCPSERVER_ACCEPTED) //处于连接状态
{
if (p != NULL) //当处于连接状态并且接收到的数据不为空时将其打印出来
{
memset(n4_to_u4.recvBuf, 0, NU_RECV_BUF_SIZE); //数据接收缓冲区清零
for (q = p; q != NULL; q = q->next) //遍历完整个pbuf链表
{
if (q->len > (NU_RECV_BUF_SIZE - data_len))
memcpy(n4_to_u4.recvBuf + data_len, q->payload,
(NU_RECV_BUF_SIZE - data_len)); //拷贝数据
else
memcpy(n4_to_u4.recvBuf + data_len, q->payload, q->len);
data_len += q->len;
if (data_len > NU_RECV_BUF_SIZE)
break; //超出TCP客户端接收数组,跳出
}
extern u32 ntouCnt; //缓冲区计数器
extern u8 ntouBuf[2048]; //缓冲区
u8 * tempBuf = &ntouBuf[ntouCnt];
if (ntouCnt + data_len < sizeof(ntouBuf))
{
ntouCnt += data_len;
//接收到的数据拷贝到系统发送缓冲区中
memcpy(tempBuf, n4_to_u4.recvBuf, data_len);
printf("reciveData=%d,sendData=%d\r\n", data_len, ntouCnt);
}
tcp_recved(tpcb, p->tot_len); //用于获取接收数据,通知LWIP可以获取更多数据
pbuf_free(p); //释放内存
ret_err = ERR_OK;
}
}
else //服务器关闭了
{
tcp_recved(tpcb, p->tot_len); //用于获取接收数据,通知LWIP可以获取更多数据
es->p = NULL;
pbuf_free(p); //释放内存
ret_err = ERR_OK;
}
return ret_err;
}[/mw_shl_code]
LWIP CubeMX配置:
我来回答