lwip之udp

2019-07-14 09:06发布

1、结构体声明

udp报文结构示意图
udp #define UDP_HLEN 8 //udp首部长度 PACK_STRUCT_BEGIN struct udp_hdr { PACK_STRUCT_FIELD(u16_t src); PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */ PACK_STRUCT_FIELD(u16_t len); PACK_STRUCT_FIELD(u16_t chksum); } PACK_STRUCT_STRUCT; PACK_STRUCT_END udp_pcb控制块声明 #define IP_PCB ip_addr_t local_ip; ip_addr_t remote_ip; u8_t so_options; u8_t tos; u8_t ttl struct udp_pcb { /* Common members of all PCB types */ IP_PCB; struct udp_pcb *next; u8_t flags; u16_t local_port, remote_port; udp_recv_fn recv; //接收回调函数 void *recv_arg; //接收回调函数的参数 }; typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); //回调函数的typedef定义 struct udp_pcb *udp_pcbs; //udp控制块链表头

2、UDP底层接口函数——udp_input

void udp_input(struct pbuf *p, struct netif *inp) { struct udp_hdr *udphdr; struct udp_pcb *pcb, *prev; struct udp_pcb *uncon_pcb; struct ip_hdr *iphdr; u16_t src, dest; u8_t local_match; u8_t broadcast; iphdr = (struct ip_hdr *)p->payload; //检查数据的合法性,并移动指针至udp的头部 if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) { pbuf_free(p); goto end; } udphdr = (struct udp_hdr *)p->payload; //检查该IP是否为广播地址 broadcast = ip_addr_isbroadcast(&current_iphdr_dest, inp); src = ntohs(udphdr->src); //源端口号 dest = ntohs(udphdr->dest); //目地端口号 { prev = NULL; local_match = 0; //与本地连接IP和端口号是否相同标志 uncon_pcb = NULL; //未连接控制块 //查找udp_pcb控制块 for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { local_match = 0; if (pcb->local_port == dest) { if ( (!broadcast && ip_addr_isany(&pcb->local_ip)) || ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest) || (broadcast && (ip_addr_isany(&pcb->local_ip) || ip_addr_netcmp(&pcb->local_ip, ip_current_dest_addr(), &inp->netmask)))) { local_match = 1; if ((uncon_pcb == NULL) && ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { uncon_pcb = pcb; } } } if ((local_match != 0) && (pcb->remote_port == src) && (ip_addr_isany(&pcb->remote_ip) || ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src))) { //连接状态的pcb放置在pcb控制块首部 if (prev != NULL) { prev->next = pcb->next; pcb->next = udp_pcbs; udp_pcbs = pcb; } else { UDP_STATS_INC(udp.cachehit); } break; } prev = pcb; } if (pcb == NULL) { pcb = uncon_pcb; } } //对接收的udp报文伪首部校验 if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &current_iphdr_dest)) { { if (udphdr->chksum != 0) { if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), IP_PROTO_UDP, p->tot_len) != 0) { pbuf_free(p); goto end; } } } if(pbuf_header(p, -UDP_HLEN)) { pbuf_free(p); goto end; } if (pcb != NULL) { //调用pcb接收回调函数处理接收的数据包 if (pcb->recv != NULL) { pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); } else { pbuf_free(p); goto end; } } else { pbuf_free(p); } } else { pbuf_free(p); } end: PERF_STOP("udp_input"); }

3、应用层接口函数

(1)发送函数
err_t udp_send(struct udp_pcb *pcb, struct pbuf *p) { return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port); } err_t udp_sendto(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port) { struct netif *netif; netif = ip_route(dst_ip); //查找网络接口 if (netif == NULL) { return ERR_RTE; } return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); } err_t udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) { struct udp_hdr *udphdr; ip_addr_t *src_ip; err_t err; struct pbuf *q; /* q will be sent down the stack */ if (pcb->local_port == 0) { err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); if (err != ERR_OK) { return err; } } //判断pbuf是否能够容纳UDP_HLEN的空间,若无则申请。 if (pbuf_header(p, UDP_HLEN)) { //申请PBUF_RAM类型的RAM空间 大小为PBUF_LINK_HLEN + PBUF_IP_HLEN + UDP_HLEN q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); /* new header pbuf could not be allocated? */ if (q == NULL) { return ERR_MEM; } if (p->tot_len != 0) { //连接两个pbuf q 和pbuf p pbuf_chain(q, p); } } else { //pbuf中已经为udp头部预留了空间 q = p; } udphdr = (struct udp_hdr *)q->payload; udphdr->src = htons(pcb->local_port); udphdr->dest = htons(dst_port); /* in UDP, 0 checksum means 'no checksum' */ udphdr->chksum = 0x0000; if (ip_addr_isany(&pcb->local_ip)) { src_ip = &(netif->ip_addr); } else { if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) { if (q != p) { pbuf_free(q); q = NULL; } return ERR_VAL; } src_ip = &(pcb->local_ip); } { udphdr->len = htons(q->tot_len); /* calculate checksum */ #if CHECKSUM_GEN_UDP if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { u16_t udpchksum; { udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len); } /* chksum zero must become 0xffff, as zero means 'no checksum' */ if (udpchksum == 0x0000) { udpchksum = 0xffff; } udphdr->chksum = udpchksum; } #endif /* CHECKSUM_GEN_UDP */ //调用ip层发送函数发送 err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif); } //新申请的pbuf q需释放 if (q != p) { pbuf_free(q); q = NULL; } return err; }
(2)控制块的相关操作函数
新建控制块,pcb->ttl = UDP_TTL; #define UDP_TTL 255 struct udp_pcb *udp_new(void) { struct udp_pcb *pcb; pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB); if (pcb != NULL) { memset(pcb, 0, sizeof(struct udp_pcb)); pcb->ttl = UDP_TTL; //生存周期 } return pcb; } 绑定某一个本地ip地址和端口号,即设置pcb->local_port,pcb->local_ip err_t udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) { struct udp_pcb *ipcb; u8_t rebind; rebind = 0; for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { if (pcb == ipcb) { rebind = 1; } if ((ipcb->local_port == port) &&(ip_addr_isany(&(ipcb->local_ip)) || ip_addr_isany(ipaddr) || ip_addr_cmp(&(ipcb->local_ip), ipaddr))) { return ERR_USE; } ip_addr_set(&pcb->local_ip, ipaddr); //设置pcb控制块中的本地ip if (port == 0) { port = udp_new_port(); //申请一个新的端口号 if (port == 0) { return ERR_USE; } } pcb->local_port = port; ////设置pcb控制块中的本地端口号 if (rebind == 0) { pcb->next = udp_pcbs; udp_pcbs = pcb; } return ERR_OK; } 连接远程主机ip号和端口号,设置pcb->remote_ip, pcb->remote_port err_t udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) { struct udp_pcb *ipcb; if (pcb->local_port == 0) { err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); if (err != ERR_OK) { return err; } } ip_addr_set(&pcb->remote_ip, ipaddr); pcb->remote_port = port; pcb->flags |= UDP_FLAGS_CONNECTED; for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { if (pcb == ipcb) { return ERR_OK; } } pcb->next = udp_pcbs; udp_pcbs = pcb; return ERR_OK; } 释放某一个pcb void udp_remove(struct udp_pcb *pcb) { struct udp_pcb *pcb2; if (udp_pcbs == pcb) { udp_pcbs = udp_pcbs->next; } else { for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { if (pcb2->next != NULL && pcb2->next == pcb) { pcb2->next = pcb->next; } } } memp_free(MEMP_UDP_PCB, pcb); } 断开某一个连接 void udp_disconnect(struct udp_pcb *pcb) { ip_addr_set_any(&pcb->remote_ip); pcb->remote_port = 0; pcb->flags &= ~UDP_FLAGS_CONNECTED; }

4、udp 应用案列

建立一个udp服务器,回显接收到的数据。 void udp_echoserver_init(void) { struct udp_pcb *upcb; err_t err; upcb = udp_new(); if (upcb) { err = udp_bind(upcb, IP_ADDR_ANY, UDP_SERVER_PORT); if(err == ERR_OK) { //注册回调函数 udp_recv(upcb, udp_echoserver_receive_callback, NULL); } else { udp_remove(upcb); printf("can not bind pcb"); } } else { printf("can not create pcb"); } } void udp_echoserver_receive_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, u16_t port) { udp_connect(upcb, addr, UDP_CLIENT_PORT); udp_send(upcb, p); udp_disconnect(upcb); pbuf_free(p); }