正点原子lwIP学习笔记——UDP协议

1.UDP协议报文结构

正点原子lwIP学习笔记——UDP协议_第1张图片
UDP的首部是8个字节,一共分成2字节的四个部分:首先是src源端口号;然后是dest目的端口号;然后是len,代表了UDP的长度;最后是chksum校验和;四个都是uint16_t的变量类型,也就是2个字节。

2.UDP数据递交流程

正点原子lwIP学习笔记——UDP协议_第2张图片

  1. 首先就是用户在应用层发送数据,把数据放入pbuf之中,其中payload此时会直接指向数据的首地址pbuf的层头是PBUF_TRANSPORT(54字节)
  2. 把数据递交给传输层,这里讲解的就是UDP协议,把payload指针上移8个字节,并添加UDP的首部;
  3. 最后把pbuf递交给网络层,payload指针再次上移20个字节,添加IP首部。

3.UDP控制块结构

正点原子lwIP学习笔记——UDP协议_第3张图片
UDP一共提供了三种接口:RAW、NETCONN以及SOCKET;RAW可以在逻辑下调用,而NETCONN以及SOCKET一定要带FreeRTOS;

如果采用RAW,那么最后两个函数,也就是recv以及recv_arg,处理网络接收数据的回调和用户自定义的参数arg,都需要手动去定义;如果是NETCONN或者是SOCKET,这两个则是lwIP自动编写好的,无需用户操作。

lwIP允许实现多个UDP的连接,就是通过next指针连接成一个单向链表;flags则是来表征当前控制块的状态,是出于连接状态还是非连接状态;

例如接收到一个数据块,这个pbuf根据解读网络层的IP首部,发现是UDP协议,就会递交给udp_input进行处理;该函数会在获取了udp的首部信息之后,遍历UDP控制块构成的单向链表;如果说当前pbuf中的目的端口与链表之中的一个udp控制块的本地端口一致,那么这个控制块就会获得这个pbuf;然后会根据控制块中的接收数据的回调函数,进行数据处理。

而NETCONN和SOCKET,原理是一样的,只不过是采用IPC方式,在操作系统中以邮箱的方式,把pbuf的指针指向对应的udp控制块,然后调用相应的回调函数。

接收数据之后,lwIP内核就会把数据递交给UDP控制块recv函数指针指向的函数。

三种接口的回调函数
RAW的传输速度是最快的,但是实现起来比较麻烦,需要了解lwIP内核;NETCONN的API就是采用IPC策略接收数据,速度稍慢但易于操作;SOCKET API高度抽象了NETCONN API,所以最易使用,但是速度最慢。

UDP控制块原理

正点原子lwIP学习笔记——UDP协议_第4张图片

  • 链接:udp的控制块会通过next指针链接成为单向链表;
  • 函数:每一个控制块都有对应的recv回调函数;
  • 端口:lwIP内核根据端口号查找pbuf对应的udp控制块;
  • 描述:每一个控制块用来描述各自网络的信息。

4.RAW接口相关函数

RAW接口简介

RAW接口是无操作系统的,回调型API接口;
RAW/callback API是lwIP的特色,在没有操作系统的裸机环境中,只能通过这种API进行开发,当然这种API也可应用于带操作系统的系统中。

优点:
内存少、效率高、兼容强、切换少。

缺点:
可读性差、逻辑复杂、易用性弱。

RAW接口UDP函数

正点原子lwIP学习笔记——UDP协议_第5张图片

  • udp_new
    通过udp_pcb新建一个pcb的控制块,然后通过memp_malloc以内存池方式申请内存,memset初始化为0,并设置pcb的ttl生存时间;
  • udp_remove
    通过pcb然后再单向链表中for循环,找到了要删除的控制块之后,调用memp_free直接释放内存,并通过链表指针删除该控制块(next指针);
  • udp_bind
    把pcb控制块绑定一个本地的IP地址和端口号;
  • udp_connect
    把pcb控制块插入单向链表中,值得注意的是,是从首部进行插入;
  • udp_disconnect
    主要就是操作udp首部的flag位置,清0表示不再链接;
  • udp_send
    内部调用udp_sendto;该函数会调用udp_sendto_if;然后继续调用udp_sendto_if_src;会对payload向上偏移8个字节,然后初始化udp的头部信息,并调用ip_output_if_src发送到IP;而该函数实际对于IPv4而言就是ip4_output_if_src;操作payload偏移然后添加IP头部信息;
  • udp_recv
    里面有三个参数,就是把用户编写的recv以及recv_arg传递给pcb结构体。

5.RAW接口的UDP实验

配置流程如下:

  1. udp_new创建一个UDP控制块:描述当前UDP的端口号、IP地址等信息;
  2. udp_connect设置目标IP地址和插入UDP PCB链表:确定发送的目标地址;
  3. udp_bind绑定本地IP地址与端口号:lwIP内核根据端口号和数据转发给目标UDP控制块;
  4. udp_recv注册接收回调函数:接收回调函数用户编写;
  5. udp_send发送数据:网络搭建完成后,可以收发数据。

实验目标:使用RAW/callback API完成UDP连接
验证:通过网络调试助手发送数据至开发板,并在LCD屏幕显示;通过KEY0发送数据到上位机中。

首先获取远程IP地址前三位与DHCP获得的地址一样,而最后一位可以根据开发板的按键进行调节;然后创建一个udpcb这个UDP的控制块,如果创建成功,就把远程地址通过IP4_ADDR传到自定义的ip_addr_t定义的远端地址rmtipaddr;然后把udppcb与rmtipaddr以及端口连接;连接成功后将本地IP地址和端口与udppcb绑定

绑定成功,进入回调函数进行操作;这里的回调函数,就是单向链表整个遍历,然后通过memcpy拷贝数据到g_lwip_demo_recvbuf这个数据接收缓冲区中

以上都完成切都成功,就会进入while循环中,并在按下KEY0后,调用lwip_udp_senddata进行数据发送;这个函数会定义一个pbuf为ptr,然后pbuf_alloc申请内存,申请成功后调用pbuf_take把用户发送的数据发给pbuf;然后通过udp_send进行UDP的发送,发送完成后pbuf_free释放掉这个pbuf的内存

总结

完成了第一个网络传输的实验,主要就是要把远程的和本地的IP地址设置好,同时要把端口设置好传给udppcb;然后就是回调函数里面调用udp_send进行数据传输,基本就完成了这个简单实验。

你可能感兴趣的:(lwIP学习,学习,笔记,udp,stm32,网络协议)