- 平台:zynq zc702
- LWIP : 1.4.1
- 是否有系统: 否
一、udp基础知识
每一个UDP连接都对应一个UDP控制块,UDP协议的实现就是对这些控制块结构成员进行操作。
为什么需要控制块链表?为了让协议栈可以实现多个连接,可以多个网络进程同时进行。最后这些控制块通过链表连接在一起。其中链接属性为外部的udp_pcbs是一个全局变量,指向控制块变量首地址。即这是一个指针变量,其数值是链表首地址。
//定义回调函数类型 typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); // 控制块结构体 struct udp_pcb *next;//将控制块构成链表 struct udp_pcb { IP_PCB;//宏定义IP控制块字段,使用到里面的本地IP地址和远端IP地址 u16_t local_port, remote_port; u8_t flags;//状态信息 /* #if LWIP_IGMP 本地和远端端口,UDP收到报文,会遍历链表,检查本地端口号和报文中目的的端口, 匹配成 功,那么调用对应控制块里面的函数指针处理报文。 ip_addr_t multicast_ip; 这样完成报文最终递交给用户程序。 */ #endif /** receive callback function */ #if LWIP_UDPLITE /** used for UDP_LITE only */ u16_t chksum_len_rx, chksum_len_tx; #endif /* LWIP_UDPLITE */ udp_recv_fn recv; //接收回调函数 void *recv_arg; //回调函数 };
当有多个udp用户进程时候就会产生多个udp控制块。用户进程接收数据包,用户进程发送数据包,根据目标IP和端口通过IP层发送出去;通过数据包里面的目标IP和端口选择udp控制块里面对应的回调函数。总体简单操作就是遍历控制块链表。 其中用户通过回调函数的方式被协议栈调用,这个就叫做raw/callback API。
二、LWIP之zynq-UDP组播
1. LWIP有3种编程接口
分别为RAW,NETCONN和SOCKET。 RAW:RAW编程接口不需要操作系统的支持,可以直接裸机使用LWIP。NETCONN和SOCKET:这两种编程接口都需要有操作系统的支持。
2、组播介绍(只用UDP才有组播)
组播地址范围是224.0.0.0到239.255.255.255。组播报文的目的地址使用D类IP地址,D类地址不能出现在IP报文的源IP地址字段。所有的信息接收者都加入到一个组内,并且一旦加入之后,流向组地址的数据立即开始向接收者传输,组中的所有成员都能接收到数据包。组播组中的成员是动态的,主机可以在任何时刻加入和离开组播组。
3、zynq7000 PS裸奔组播
移植关键点:
(1)打开 LWIP_IGMP
宏 IGMP(Internet Group Management Protocol,Internet 组管理协议)是因特网协议家族中的一个组播协议。该协议运行在主机和组播路由器之间,主机通过IGMP通知路由器希望接收或离开某个特定组播组的信息。
(2)关闭MAC层过滤功能
在set_option中设置允许所有数据流进入,否则无法接受到组播数据,会被MAC过滤掉。
(3)循环检测MAC层数据
在while(1)中循环检测数据接受情况:
调用 xemacif_input(netif);
4、组播初始化代码
void udp_Multicast(void) { err_t err; struct udp_pcb *udppcb; struct ip_addr group_addr; IP4_ADDR(&group_addr,239,0,1,2); //组播池 err = igmp_joingroup(IP_ADDR_ANY,(struct ip_addr*)(&group_addr)); if (err != ERR_OK) { printf("igmp_joingroup error \n"); return ; } udppcb = udp_new(); if(udppcb) { udp_bind(udppcb,IP_ADDR_ANY,UDP_LOCAL_PORT); udp_recv(udppcb , udp_demo_recv , NULL); } }
5、组播初始化代码
zynq 下默认组播是被MAC层过滤掉的,必须配置,否则,会接收不到数据。
备注:无需循环调用igmp_tmr() 函数。