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

11.12.2 udp_send():UDP发送数据函数从用户的角度看,用户前期配置好UDP控制块后,后面发送数据只需要提供两个参数:UDP控制块和需要发送的数据即可 。
所以就有了udp_send()函数 , 该函数的实现是层层封装UDP发送数据的基函数udp_sendto_if_src()实现的:udp_send() --> udp_sendto() --> udp_sendto_if() --> udp_sendto_if_src()
udp_send():没有指定远端IP和端口号则使用这个UDP PCB中的 。

  • udp_pcb *pcb:负责本次发送的UDP控制块 。
  • struct pbuf *p:需要发送的UDP数据 。
/** * @ingroup udp_raw * Sends the pbuf p using UDP. The pbuf is not deallocated. * * @param pcb UDP PCB used to send the data. * @param p chain of pbuf's to be sent. * * The datagram will be sent to the current remote_ip & remote_port * stored in pcb. If the pcb is not bound to a port, it will * automatically be bound to a random port. * * @return lwIP error code. * - ERR_OK. Successful. No error occurred. * - ERR_MEM. Out of memory. * - ERR_RTE. Could not find route to destination address. * - ERR_VAL. No PCB or PCB is dual-stack * - More errors could be returned by lower protocol layers. * * @see udp_disconnect() udp_sendto() */err_tudp_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;}/* 使用这路UDP控制块中配置的远端IP和远端端口号 */return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);}udp_sendto():指定远端IP和远端端口号的UDP发送 。
  • struct udp_pcb *pcb:负责本次发送的UDP控制块 。
  • struct pbuf *p:需要发送的数据的pbuf 。
  • ip_addr_t *dst_ip:远端IP地址 。
  • u16_t dst_port:远端端口号地址 。
  • 传入参数校验 。
  • 还需要指定本地网卡:
    • 如果UDP控制块已经绑定了本地网卡 , 则直接调用该网卡即可 。
    • 否则 , 需要根据远端IP地址 , 用ip4_route_src()去路由匹配 。这个匹配逻辑可以参考前面IP章节 。
  • 然后调用udp_sendto_if()发送出去 。
/** * @ingroup udp_raw * Send data to a specified address using UDP. * * @param pcb UDP PCB used to send the data. * @param p chain of pbuf's to be sent. * @param dst_ip Destination IP address. * @param dst_port Destination UDP port. * * dst_ip & dst_port are expected to be in the same byte order as in the pcb. * * If the PCB already has a remote address association, it will * be restored after the data is sent. * * @return lwIP error code (@see udp_send for possible error codes) * * @see udp_disconnect() udp_send() */err_tudp_sendto(struct udp_pcb *pcb, struct pbuf *p,const ip_addr_t *dst_ip, u16_t dst_port){struct netif *netif;/* 参数校验 */LWIP_ERROR("udp_sendto: invalid pcb", pcb != NULL, return ERR_ARG);LWIP_ERROR("udp_sendto: invalid pbuf", p != NULL, return ERR_ARG);LWIP_ERROR("udp_sendto: invalid dst_ip", dst_ip != NULL, return ERR_ARG);/* UDP控制块本地IP类型和目标IP类型要一致 */if (!IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) {return ERR_VAL;}LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));if (pcb->netif_idx != NETIF_NO_INDEX) {/* 如果已经绑定了网卡,则直接使用该网卡发送UDP报文 */netif = netif_get_by_index(pcb->netif_idx);} else { /* 没有绑定网卡就需要匹配 */#if LWIP_MULTICAST_TX_OPTIONS /* 多播TX功能 */netif = NULL;if (ip_addr_ismulticast(dst_ip)) {/* 如果UDP报文的目的IP地址是多播地址,则使用多播网卡来发送 */if (pcb->mcast_ifindex != NETIF_NO_INDEX) {netif = netif_get_by_index(pcb->mcast_ifindex);}#if LWIP_IPV4else#if LWIP_IPV6if (IP_IS_V4(dst_ip))#endif /* LWIP_IPV6 */{/* 如果当前UDP指定的多播地址不是任意也不是广播,就需要通过路由去匹配 */if (!ip4_addr_isany_val(pcb->mcast_ip4) &&!ip4_addr_eq(&pcb->mcast_ip4, IP4_ADDR_BROADCAST)) {/* 通过UDP本地IP和多播IP去匹配本地网卡 */netif = ip4_route_src(ip_2_ip4(&pcb->local_ip), &pcb->mcast_ip4);}}#endif /* LWIP_IPV4 */}if (netif == NULL) /* 还没有指定网卡 */#endif /* LWIP_MULTICAST_TX_OPTIONS */{/* 通过UDP本地IP和目的IP去匹配网卡 */netif = ip_route(&pcb->local_ip, dst_ip);}}if (netif == NULL) {/* 找不到适合发送的当前UDP报文的网卡,则丢弃 */LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to "));ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, dst_ip);LWIP_DEBUGF(UDP_DEBUG, ("\n"));UDP_STATS_INC(udp.rterr);return ERR_RTE;}/* 通过以下API实现发送UDP报文 */#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDPreturn udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum);#else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */return udp_sendto_if(pcb, p, dst_ip, dst_port, netif);#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */}

推荐阅读