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 */}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 【什么是妖股】妖股是什么意思
- .net 温故知新:【9】.NET日志记录 ILogger使用和原理
- 【k8s连载系列】2. k8s整体架构
- 安卓手机截屏模式怎么设置(手机截屏模式怎么设置)
- ubantu18.04@Intel 82545EM 【安装文档】TRex流量分析仪保姆级安装指南--基于VMware虚拟机
- 星之彼端丹铜事件该如何选择
- iphone怎么刷机(iphone刷机教程)
- 《正义联盟》中超人是怎么死的
- 王者荣耀娜可露露前尘镜中文语音包怎么设置
- 《三国演义》中曹操的大将许褚是怎么死的(三国许褚做了哪些大事)