【lwip】11-UDP协议&源码分析( 三 )

udp_port累加管理 。
其初始值有两次初始:第一次是变量赋值,第二次是调用udp_init()进行随机初始 。
变量初始值:
/* last local UDP port */static u16_t udp_port = UDP_LOCAL_PORT_RANGE_START;随机初始化:

  • 需要开启LWIP随机宏LWIP_RAND
/** * Initialize this module. */voidudp_init(void){#ifdef LWIP_RANDudp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND());#endif /* LWIP_RAND */}11.10.3 udp_new_port()端口号申请端口号申请是有udp_port进行累加,溢出就复位到UDP_LOCAL_PORT_RANGE_START
/** * Allocate a new local UDP port. * * @return a new (free) local UDP port number */static u16_tudp_new_port(void){u16_t n = 0;struct udp_pcb *pcb;again:if (udp_port++ == UDP_LOCAL_PORT_RANGE_END) { /* 累加获取 */udp_port = UDP_LOCAL_PORT_RANGE_START; /* 溢出复位 */}/* Check all PCBs. */for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { /* 检查是否有重复 */if (pcb->local_port == udp_port) { /* 重复 */if (++n > (UDP_LOCAL_PORT_RANGE_END - UDP_LOCAL_PORT_RANGE_START)) {return 0; /* 如果所有端口号都重复了,返回申请失败 */}goto again; /* 重新申请 */}}return udp_port; /* 申请成功 */}11.11 UDP控制块操作函数UDP控制块的操作函数相对简单,因为没有流量控制、没有确认机制等等 。
11.11.1 udp_new():新建UDP控制块udp_new()
  • MEMP_UDP_PCB内存池中获取UDP控制块资源 。
  • 初始化部分字段 。
/** * @ingroup udp_raw * Creates a new UDP pcb which can be used for UDP communication. The * pcb is not active until it has either been bound to a local address * or connected to a remote address. * @see MEMP_NUM_UDP_PCB * * @return The UDP PCB which was created. NULL if the PCB data structure * could not be allocated. * * @see udp_remove() */struct udp_pcb *udp_new(void){struct udp_pcb *pcb;LWIP_ASSERT_CORE_LOCKED(); /* 内核锁确认 */pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB); /* 申请UDP控制块资源 */if (pcb != NULL) {memset(pcb, 0, sizeof(struct udp_pcb));pcb->ttl = UDP_TTL; /* UDP数据出口默认的TTL值 */#if LWIP_MULTICAST_TX_OPTIONS /* 多播TX相关 */udp_set_multicast_ttl(pcb, UDP_TTL);#endif /* LWIP_MULTICAST_TX_OPTIONS */}return pcb;}11.11.2 udp_remove():删除UDP控制块udp_remove()
  • struct udp_pcb *pcb:需要删除的UDP控制块 。
/** * @ingroup udp_raw * Removes and deallocates the pcb. * * @param pcb UDP PCB to be removed. The PCB is removed from the list of * UDP PCB's and the data structure is freed from memory. * * @see udp_new() */voidudp_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);/* 先从udp_pcbs链表中移除 */if (udp_pcbs == pcb) {/* 如果当前UDP控制块是udp_pcbs的链表头 , 则直接更新链表头即可移除 */udp_pcbs = udp_pcbs->next;} else { /* 需要遍历udp_pcbs,把当前UDP控制块移除 */for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {if (pcb2->next != NULL && pcb2->next == pcb) {pcb2->next = pcb->next;break;}}}/* 释放内存资源 */memp_free(MEMP_UDP_PCB, pcb);}11.11.3 udp_bind():绑定控制块当UDP服务于应用程序时,数据流需要底层和应用层进行对接,就需要把UDP控制块绑定到本地IP和端口号 。
绑定控制块时需要注意的是:
  1. 检查是否有PCB已经绑定了当前IP和端口号 。
  2. 当前PCB有没有已经插入了udp_pcbs链表 。
小笔记:在没有设置SOF_REUSEADDR选项功能时 , 需要确保一个UDP报文最多只能到达一个应用程序 。即是一个网络接口中的一个端口号 。需要注意的是任意IP 。
udp_bind()