现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

用lwip发送大量数据时,遇到的问题解答记录

2019-05-05 06:52 工业·编程 ⁄ 共 2126字 ⁄ 字号 暂无评论

1、概述

lwip是轻量型的TCP/IP实现,只需10几KB的RAM和40几KB的ROM就能够跑起来,适合应用于嵌入式设备的网络通信。有牛人Adam Dunkels发明,提供给用户上那种接口

RAW TCP/IP、Squential API, BSD API(也就是常说的socket编程),前者编程稍微复杂点,协议和应用程序在一个进程里面,但是效率高。中者首先要操作系统的支持,但是一旦实现了操作系统模拟层的实现,编程妥妥的。后者是为了符合人们使用socket编程的习惯而模拟的socket实现。所以王者乃RAW TCP/IP。网上提供了源码的下载,现在已经更新至1.4.x(doc 开发与移植指导文档, src 源码 test 测试例子),doc里面罗列了RAW TCP/IP的开发接口函数。

2、demo搭建:

服务器端:

0 open_tap()里面选择适合的网卡

1 开辟新进程 sys_thread_new("http thread",server_init, NULL, 0, 0);

2 设定网址和默认路由器 netif_add(&netif, &ip, &mask, &gw, NULL, ethernetif_init, tcpip_input);

3 在server_init里面 分别调用pcb = tcp_new(); tcp_bind(pcb, IP_ADDR_ANY, 8000);pcb = tcp_listen(pcb);

tcp_accept(pcb, server_accept); tcp_poll(pcb, tcp_poll, 10);// 每5s执行一次tcp_poll;

4 当有新的连接到来时,即有新的数据接收时, server_accept 就好调用。在server_accept里面注册调用函数tcp_recv(pcb, server_recv);

此后每次新的数据过来时,就会调用server_recv函数。

5 在函数 static err_t server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)里面对pbuf进行分析,要注意p->next的值。

并且借鉴其他资料知道立即要调用tcp_recevd;很神秘的告诉你要调用否则不好使。后面这里有重要发现!!!。

6 调用pbuf_free函数,来释放pbuf;

客服端

0~2步基本相同

3在client_init里面 分别调用pcb = tcp_new(); ret_val = tcp_connect(pcb, &dest, 8000, client_connected);

4 在client_connected里面发送连接请求。同时调用tcp_accept(pcb, client_recv)来注册数据接收处理回调函数。

5 在static err_t client_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);对接收到的数据进行处理

类似server_recv。

搭建完成之后:发现,在server_recv 函数里面只能够tcp_write 128个字节的数据。当发送大于128个数据时,就会只能够接收128个数据。

找了半天发现[2]是由opt.h里面的参数MSS 128决定的, 另外还要注意一个参数即TCP_SND_WND 256。

改变这两个后,发送比TCP_SND_WND小且比MSS大的数据时, 客户端可以接受到一次等于MSS的数据。

试了各种策略后,客户端只接收一次。我们甚至怀疑是回调函数注册一次只能使用一次的问题,都无效。

后面查询各种资料[3], 后面发现英文资料lwip-user给出了很多启示:

包括分析TCP segment(底层自行封装成不同packet,不带ACK) 和 IP segment(>MTU时,会带ACK)

了解了opt.h中:

MSS (the smaller, the better) 128

TCP_SND_BUF 256

MEM_SIZE (1600) HEAP SIZE 如果tcp_write 用COPY的方式时是需要设置较大的值;

TCP_SND_QUEUELEN  4*(TCP_SND_BUF/tcp_mss)(最小为除式的两倍);

MEMP_NUM_TCP_SEG: 至少跟上面一样大

MEMP_NUM_PBUF(16) --->32

TCP_WND 2048 接收窗口,接收多少个数据包的问题。

今天通过wireshark抓包发现,1.15 端发送给了 1.111端后面多于MSS的数据报文,而且发送端一直发送MSS长度的报文,可以得知应该是接收端的没有应答正确。前面提到的tcp_recevd调用的是tcp_ack函数。其实就是对接收到的数据进行应答但是同时发现有一个好用的函数 tcp_ack_now(pcb),是直接发送应答,因为后面跟了tcp_output(pcb)函数。

并且要了解flags 设置 pcb->flags |= TF_NODELAY | TF_ACK_NOW; len = tcp_sndbuf(pcb);会告知剩余的buf的长度并且多次发送的时候可以设置这个值,从而手动告知系统还有多少buf可以发送,从而实现了多次发送的操作。

改了这两处之后,实验可以发送32000个字节,不错。

给我留言

留言无头像?