其实发送一个包就这么多.
/* UDP 缓冲区申请 */
udpbuf = netbuf_new();
/* 申请内存 */
netbuf_alloc(udpbuf, strlen((char *)udpdemo_buf));
/* 把数据复制到payload里去. */
memcpy(udpbuf->p->payload, (void *)udpdemo_buf, strlen((const char *)udpdemo_buf));
/* payload 其实也可以直接修改. */
((uint32_t *)udpbuf->p->payload)[0] = xTaskGetTickCount();
/* 这一步把数据发送出去. */
err = netconn_send(udpconn, udpbuf);
/* UDP总会发成功的. */
netbuf_delete(udpbuf);
其中netbuf_new跟进去,发现其实就是一个calloc.
netbuf_alloc就是申请到内存,指针指向申请到的位置.
memcpy是标准函数,不用多说.
netbuf_delete就是删除calloc到的东西.
那么其实就剩下了netconn_send,这个函数看起来应该比较复杂,因为其他地方什么都没干.进去一看,还是apimsg的安全调用.不得不说安全性十足,而我们一开始就知道,直接看fn就行,其他都是安全需要.
1396行的错误判断,我们一开始就见过.就是如果这个conn有问题,就不要往下继续了.
接下来判断PCB是有效的,再跳转到NETCONN_UDP,明显这个函数只适合UDP.LWIP_CHECKSUM_ON_COPY又刚好是打开的,那么就是要校验.而后续一个是udp_send_chksum,一个是udp_sendto_chksum.
如果是本机发,就走到上面得判断,下面的判断就是有目标端口,目标地址什么的,其实最终是调用udp_sendto_chksum的.
进去就是ip_route,因为IP_IS_ANY_TYPE_VAL恒定为0,所以没被编译进去.
实际上,包就是从ip_route这一段,数据就出去了.这就是到达了IP层,记得七层模型里面,TCP还在比较靠上的一层.
可见,ip_route是查找到源网卡,以便后续构建.接着在sendto里面再获取了本地的src_ip(发送者IP).
到了udp_sendto_if_src_chksum,里面很多判断,这个代码尤其长.
/** Same as udp_sendto_if_src(), but with checksum */
err_t
udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip,
u16_t dst_port, struct netif *netif, u8_t have_chksum,
u16_t chksum, const ip_addr_t *src_ip)
{
#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */
struct udp_hdr *udphdr;
err_t err;
struct pbuf *q; /* q will be sent down the stack */
u8_t ip_proto;
u8_t ttl;
if ((pcb == NULL) || (dst_ip == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, src_ip) ||
!IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) {
return ERR_VAL;
}
#if LWIP_IPV4 && IP_SOF_BROADCAST
/* broadcast filter? */
if (!ip_get_option(pcb, SOF_BROADCAST) &&
#if LWIP_IPV6
IP_IS_V4(dst_ip) &&
#endif /* LWIP_IPV6 */
ip_addr_isbroadcast(dst_ip, netif)) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p
"