LwIP 代码分析(netconn_recv分析) – 第七集

/ 1评 / 15

netconn_send只用于UDP和RAW(其中RAW还没什么人用),但是netconn_recv是用于TCP,UDP都适合的.
可见netconn_recv针对UDP就是直接调用了netconn_recv_data.

进去后就是等邮箱,如果没有东西,自然就超时了.

那邮箱又是怎么解锁的呢?这就涉及从最底层开始分析,之前是构造包,现在是解码包.但是先不开,我们看一旦解锁,buf就有了,证明是给了buf.

这个锁是个Queue,他就是存着buf的数据.那么,最重要就是解锁,但是通过搜索,解锁函数实在太多,老实从这里开始分析.

已知low_level_input是把数据存到p里面,p是pbuf类型,netif->input负责解码包,解码完还要扫地.而netif->input又是tcpip_input,因为我们有以太网属性的,所以只会走第一个if分支.

也就是进入到tcpip_inpkt,然后找时机跳ethernet_input.看到trypost里面,高亮处显示的mbox是个Queue,他在lwip初始化时候就一直有效,就是他用来传输各种东西.

但是input函数不好分析,为什么呢,因为以太网里面很多广播包,比如ARP的什么的,他也会路由到这里面.解锁后,tcpip_thread的第102行代码得以执行.

这才是接收daemon啊.调用的type是TCPIP_MSG_INPKT.随即路由到断点处.

一进来就分析出以太网头,因为他在最前面.

进一步判断是否为多播,广播包.

因为多播,广播,他第一个MAC地址的最低位必须为1的.多播就是0x01,广播是0xFF.
然后继续分离是ARP还是以太网包,我们一般的数据,都是IP包.比如ARP的,就没有IP头.

看图如果是IP数据就会执行到ip4_input.

ARP包只要有设备,一直都会有,到处问.因为他基本是广播.

或者是互相确认.

IP包是包含协议的,所以要从IP包中才能分析出协议.

果然他也是读取协议,再下一步处理.

进入后,就得找对应的PCB,来处理这个数据块.

只要PCB找得到,for_us就是有效的,但是,由于UDP是无状态协议,他可能发到我们没注册的位置,那么如果他目标地址是我们的,for_us也是对的.

搞定后就去UDP头.

去完头就是数据,就是OK的.没有细分析,但是LwIP结构是一开始我们就做过一个分析,现在就明白多了.
最后数据搞好调用pcb->recv函数,这个在我们netconn_new时候指定为recv_udp,为什么还要做这一步,因为像DHCP这些也是UDP,他们也要用UDP底层,所以就得分开处理这个状况.
最后在recv_udp出解锁接收的mbox.

这样,netconn_recv就可以收到数据了.(不会因为mbox拿不到而TIMEOUT).回顾netconn_recv函数.

这有一个关于丢包的事情.我们假设在netconn_recv收到了数据,并完成了解锁,此时又从网卡收到数据.重新压到mbox里,并且mbox深度有限,默认DEFAULT_UDP_RECVMBOX_SIZE为6,也就是队列能容纳6次待处理的数据,如果压入一次性压了7次,没来得及取走,就丢包了,可能唯一解决办法是加大buf,但是内存又是有限的,所以,这是个矛盾的话题啊.
改善方法,可以是新增一个任务,最高优先级,一直阻塞在等待数据,这样可以改善下丢包.另外,我的例子代码可以改成,一直接受,直到没有再去发,这样看起来接受总是高优先级的.

  1. 1说道:

    感谢大神!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注