lwip有3种编成接口,分别为:RAW、NETCONN和SOCKET。

RAW:RAW编程接口不需要操作系统的支持,可以直接裸机使用LWIP,但是RAW的编程接口比较复杂,RAW使用的是回调机制,需要大家了解回调函数。
NETCONN和SOCKET:这两种编程接口需要有操作系统的支持,否则的话没法使用,但是这两种接口使用起来比较简单。

udp控制块
控制块里面描述了一个UDP连接的所有信息,包括源端口号、目的端口号、源IP地址、目的IP地址等。用户的UDP编程,本质上都是对UDP的控制块进行操作。
系统为每一个连接分配一个UDP控制块,并将其组织在一个链表上,当UDP层收到IP层的报文时,会去遍历整个链表,找出与报文部首匹配的控制块,并调用控制块中注册的函数来完成报文的处理。

在udp.h中:

struct udp_pcb {/** Common members of all PCB types */IP_PCB;/* Protocol specific PCB members */struct udp_pcb *next;//标识UDP控制块状态信息u8_t flags;/** ports are in host byte order */u16_t local_port, remote_port;#if LWIP_MULTICAST_TX_OPTIONS
#if LWIP_IPV4/** outgoing network interface for multicast packets, by IPv4 address (if not 'any') */ip4_addr_t mcast_ip4;
#endif /* LWIP_IPV4 *//** outgoing network interface for multicast packets, by interface index (if nonzero) */u8_t mcast_ifindex;/** TTL for outgoing multicast packets */u8_t mcast_ttl;
#endif /* LWIP_MULTICAST_TX_OPTIONS */#if LWIP_UDPLITE/** used for UDP_LITE only */u16_t chksum_len_rx, chksum_len_tx;
#endif /* LWIP_UDPLITE *//** receive callback function *///回调函数//UDP协议接收数据后处理过程//lwip内核调用udp_recv_fn recv;//回调函数的参数/** user-supplied argument for the recv callback */void *recv_arg;
};

udp raw编程接口

  • 新建一个UDP的PCB控制块
struct udp_pcb *
udp_new(void)
{struct udp_pcb *pcb;LWIP_ASSERT_CORE_LOCKED();pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB);/* could allocate UDP PCB? */if (pcb != NULL) {/* UDP Lite: by initializing to all zeroes, chksum_len is set to 0* which means checksum is generated over the whole datagram per default* (recommended as default by RFC 3828). *//* initialize PCB to all zeroes */memset(pcb, 0, sizeof(struct udp_pcb));pcb->ttl = UDP_TTL;
#if LWIP_MULTICAST_TX_OPTIONSudp_set_multicast_ttl(pcb, UDP_TTL);
#endif /* LWIP_MULTICAST_TX_OPTIONS */}return pcb;
}

如果MEMP_UDP_PCB类型的内存池用完就无法申请,个数可以在lwipotps.h中定义。

  • 将一个pcb控制块从链表中删除,并释放这个控制块的内存
void
udp_remove(struct udp_pcb *pcb)
{struct udp_pcb *pcb2;LWIP_ASSERT_CORE_LOCKED();LWIP_ERROR("udp_remove: invalid pcb", pcb != NULL, return);mib2_udp_unbind(pcb);/* pcb to be removed is first in list? */if (udp_pcbs == pcb) {/* make list start at 2nd pcb */udp_pcbs = udp_pcbs->next;/* pcb not 1st in list */} else {for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {/* find pcb in udp_pcbs list */if (pcb2->next != NULL && pcb2->next == pcb) {/* remove pcb from list */pcb2->next = pcb->next;break;}}}memp_free(MEMP_UDP_PCB, pcb);
}
  • 为UDP的PCB绑定一个本地ip地址和端口号

实质是设置udp_pcb内部本地ip、port字段并把他添加到udp_pcbs链表上

err_t
udp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port)
{struct udp_pcb *ipcb;u8_t rebind;
#if LWIP_IPV6 && LWIP_IPV6_SCOPESip_addr_t zoned_ipaddr;
#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */LWIP_ASSERT_CORE_LOCKED();#if LWIP_IPV4/* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */if (ipaddr == NULL) {ipaddr = IP4_ADDR_ANY;}
#else /* LWIP_IPV4 */LWIP_ERROR("udp_bind: invalid ipaddr", ipaddr != NULL, return ERR_ARG);
#endif /* LWIP_IPV4 */LWIP_ERROR("udp_bind: invalid pcb", pcb != NULL, return ERR_ARG);LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = "));ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE, ipaddr);LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port));rebind = 0;/* Check for double bind and rebind of the same pcb */for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {/* is this UDP PCB already on active list? */if (pcb == ipcb) {rebind = 1;break;}}
  • 连接到指定的ip地址主机的指定端口号,其实就是设置pcb控制块的remote_ip和remote_port
err_t
udp_connect(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port)
{struct udp_pcb *ipcb;LWIP_ASSERT_CORE_LOCKED();LWIP_ERROR("udp_connect: invalid pcb", pcb != NULL, return ERR_ARG);LWIP_ERROR("udp_connect: invalid ipaddr", ipaddr != NULL, return ERR_ARG);if (pcb->local_port == 0) {err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);if (err != ERR_OK) {return err;}}ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr);
#if LWIP_IPV6 && LWIP_IPV6_SCOPES/* If the given IP address should have a zone but doesn't, assign one now,* using the bound address to make a more informed decision when possible. */if (IP_IS_V6(&pcb->remote_ip) &&ip6_addr_lacks_zone(ip_2_ip6(&pcb->remote_ip), IP6_UNKNOWN)) {ip6_addr_select_zone(ip_2_ip6(&pcb->remote_ip), ip_2_ip6(&pcb->local_ip));}
#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */pcb->remote_port = port;pcb->flags |= UDP_FLAGS_CONNECTED;LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to "));ip_addr_debug_print_val(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,pcb->remote_ip);LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->remote_port));/* Insert UDP PCB into the list of active UDP PCBs. */for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {if (pcb == ipcb) {/* already on the list, just return */return ERR_OK;}}/* PCB not yet on the list, add PCB now */pcb->next = udp_pcbs;udp_pcbs = pcb;return ERR_OK;
}
  • 断开连接
void
udp_disconnect(struct udp_pcb *pcb)
{LWIP_ASSERT_CORE_LOCKED();LWIP_ERROR("udp_disconnect: invalid pcb", pcb != NULL, return);/* reset remote address association */
#if LWIP_IPV4 && LWIP_IPV6if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {ip_addr_copy(pcb->remote_ip, *IP_ANY_TYPE);} else {#endifip_addr_set_any(IP_IS_V6_VAL(pcb->remote_ip), &pcb->remote_ip);
#if LWIP_IPV4 && LWIP_IPV6}
#endifpcb->remote_port = 0;pcb->netif_idx = NETIF_NO_INDEX;/* mark PCB as unconnected */udp_clear_flags(pcb, UDP_FLAGS_CONNECTED);
}
  • 通过一个PCB控制块发送数据
err_t
udp_send(struct udp_pcb *pcb, struct pbuf *p)
{LWIP_ERROR("udp_send: invalid pcb", pcb != NULL, return ERR_ARG);LWIP_ERROR("udp_send: invalid pbuf", p != NULL, return ERR_ARG);if (IP_IS_ANY_TYPE_VAL(pcb->remote_ip)) {return ERR_VAL;}/* send to the packet using remote ip and port stored in the pcb */return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);
}
  • 接收函数

接收处理是ip层收到ip数据报后通过协议字段判断是udp后调用udp_input
udp_input根据报文中源目ip、port寻找匹配的udp控制块,
port匹配原则如下,
1.首先寻找与报文中源目port都匹配的且处于连接状态的控制块,若没有
2.寻找与报文中目地port匹配的非连接状态的控制块
ip匹配原则如下,
1.报文是非广播包,且本地绑定的是任意ip
2.绑定的ip和报文目的ip一致
3.对于广播包,控制块的ip要和广播包在同一网段
如果匹配不到会返回一个端口不可达icmp报文
匹配好后就调用之前注册的回调函数,注意收到的数据包由用户释放,即回调函数内部释放。代码在udp.c,我就不粘贴了。

LWIP学习笔记(5)RAW_UDP实验相关推荐

  1. 【LWIP】LWIP协议|相关知识汇总|LWIP学习笔记

    这里作为一个汇总帖把,把以前写过的LWIP相关的博客文章汇总到一起,方便自己这边查找一些资料. 收录于: [LWIP]LWIP协议|相关知识汇总|LWIP学习笔记 LWIP协议 [LWIP]LWIP网 ...

  2. STM32学习笔记:按键实验

    STM32学习笔记:按键实验 一.所使用的函数 1.时钟使能函数 RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState New ...

  3. LwIP学习笔记——STM32 ENC28J60移植与入门

    0.前言 去年(2013年)的整理了LwIP相关代码,并在STM32上"裸奔"成功.一直没有时间深入整理,在这里借博文整理总结.LwIP的移植过程细节很多,博文也不可能一一详解个别 ...

  4. 唤醒手腕Python全栈工程师学习笔记(微机实验篇)

    01.树莓派安装操作系统 官网下载网址:https://www.raspberrypi.org/downloads/ 官网为不同的电脑操作系统提供了烧录软件,大家可以根据不同的操作系统下载对应软件.而 ...

  5. LWIP学习笔记(3)LWIP数据包管理结构pbuf

    pbuf:LWIP是TCP/IP协议栈的一种具体体现,本质就是对数据包的处理,在LWIP中使用一个被称为pbuf的结构体管理数据包,LWIP源码中的pbuf.c和pbuf.h这两个文件就是关于pbuf ...

  6. ZYNQ学习笔记——高速ADDA实验

    文章目录 高速AD/DA实验 AD/DA原理 分类 高速AD/DA简介 硬件设计 程序设计 顶层模块(hs_ad_da) AD 数据接收模块 DA数据发送模块 遇到的问题 高速AD/DA实验 AD/D ...

  7. LWIP学习笔记---网际控制报文协议ICMP

    网际控制报文协议 背景 相关概念 报文类型 报文格式 差错报文 查询报文 代码实现 数据结构 发送差错报文代码实现 回送报文请求 背景 IP协议并不完美,在传递数据时提供的是一种无连接的不可靠数据报交 ...

  8. MIT 6.828 学习笔记4 Lab2实验报告

    Lab2实验报告 Execrise 1 static void *boot_alloc(uint32_t n) {static char *nextfree;char *result;if (!nex ...

  9. ANSYS学习笔记——汽车绕流实验

    2D平面汽车模型绕流实验 ICEM建模和画非结构网格 #打开ICEM,File->change working directory setting->C盘,确定(软件第一次使用时需要进行这 ...

最新文章

  1. 【FFmpeg】降低转码延迟方法、打印信息详解、refcounted_frames详解
  2. 栈,堆,值类型,引用类型,装箱,拆箱 .NET中 6个重要的概念
  3. Cartographor定位-shell脚本:不停拉起死掉的程序和脚本
  4. .NET Core HttpClient请求异常思考
  5. 【CodeForces - 1105C】Ayoub and Lost Array(线性计数dp)
  6. updatebyprimarykeyselective返回什么是成功_嫦娥五号发射升空成功!!!
  7. mariadb与mysql的兼容_「MySQL架构」MariaDB versus MySQL: Compatibility
  8. web靶机:kali linux 2.0下搭建DVWA渗透测试演练平台
  9. Android 获取手机号及运营商信息
  10. Android - Broadcast机制
  11. LayaAir 缓动动画
  12. java 001 002_java笔记0x002:操作符
  13. 网络子系统55_ip协议分片重组_加入ipq
  14. 汇编语言指令是机器指令的符号化
  15. PS教程第六课:魔棒工具进行抠图
  16. Exchange ProxyShell复现
  17. 【独行秀才】macOS Monterey 12.0 Beta4(21A5294g)原版镜像
  18. linux 免费教程下载,Linux系统入门教程
  19. QT 使用QZXing生成,解析二维码跟条码
  20. 【MySQL数据库系列】一、认识数据库、建库建表操作

热门文章

  1. 【带你吃透C++】模板详解
  2. cocos creator 划动屏幕以移动摄像机
  3. 【数据结构必备基本知识】数据结构常用预定义常量、类型及头文件
  4. java通过反射机制测试private构造函数
  5. python爬虫抖音_Python 爬虫——抖音App视频抓包
  6. 2023微信小程序校园活动报名管理系统(SSM+mysql)-JAVA.JSP(论文+开题报告+运行)
  7. Linux | PCIe Hotplug | 概念及工作原理的不完全总结
  8. 求问,固态硬盘格式化问题
  9. python中定义常数关键字
  10. 委托与事件-观察者设计模式_老鹰捉小鸡