lwip之udp

来源:互联网 发布:mac妆前乳专柜价格 编辑:程序博客网 时间:2024/05/16 23:33

1、结构体声明

udp报文结构示意图
udp

#define UDP_HLEN 8  //udp首部长度PACK_STRUCT_BEGINstruct 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);}
0 0