我是靠谱客的博主 笨笨酒窝,最近开发中收集的这篇文章主要介绍contiki学习笔记-udp-server.c文件详细的解析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

上文中已经将大部分的复杂的用到的函数给解释了一下。刚刚看了一下http://blog.csdn.net/xukai871105/article/details/23615211里的地址转换原理,顿时又将其中两个一直不明白的地方函数给弄懂了,稍后会将这两个函数给补充完整,这样子,服务器端的代码就能大部分理解了。OK开始吧。先贴PROCESS_THREAD()的代码,将必要的进行注释。

PROCESS_THREAD(udp_server_process, ev, data)
{
#if UIP_CONF_ROUTER
  uip_ipaddr_t ipaddr;
#endif /* UIP_CONF_ROUTER */

  PROCESS_BEGIN();
  PRINTF("UDP server startedn");

#if RESOLV_CONF_SUPPORTS_MDNS
  resolv_set_hostname("contiki-udp-server");//设置主机的名字
#endif

#if UIP_CONF_ROUTER
  uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);//设置IPV6地址中后面部分的
  uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);//设置IPV6地址中的前面部分Initializer部分
  uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);//为地址的后面部分添加前缀
#endif /* UIP_CONF_ROUTER */

  print_local_addresses();

  server_conn = udp_new(NULL, UIP_HTONS(3001), NULL);
  udp_bind(server_conn, UIP_HTONS(3000));

  while(1) {
    PROCESS_YIELD();
    if(ev == tcpip_event) {
      tcpip_handler();
    }
  }

  PROCESS_END();
}
这里着重说一下下面这两个函数。

void
uip_ds6_set_addr_iid(uip_ipaddr_t *ipaddr, uip_lladdr_t *lladdr)
{
  /* We consider only links with IEEE EUI-64 identifier or
   * IEEE 48-bit MAC addresses */
#if (UIP_LLADDR_LEN == 8)
  memcpy(ipaddr->u8 + 8, lladdr, UIP_LLADDR_LEN);
  ipaddr->u8[8] ^= 0x02;
#elif (UIP_LLADDR_LEN == 6)
  memcpy(ipaddr->u8 + 8, lladdr, 3);
  ipaddr->u8[11] = 0xff;
  ipaddr->u8[12] = 0xfe;
  memcpy(ipaddr->u8 + 13, (uint8_t *)lladdr + 3, 3);
  ipaddr->u8[8] ^= 0x02;
#else
#error uip-ds6.c cannot build interface address when UIP_LLADDR_LEN is not 6 or 8
#endif
}
       这个函数呢,就是为了给IPV6地址的identifier赋值。IPV6地址呢分为两部分,但是是共享一段内存,对两个的任意一个赋值都可以。源代码中可以找到

typedef union uip_ip6addr_t {
  uint8_t  u8[16];			/* Initializer, must come first. */
  uint16_t u16[8];
} uip_ip6addr_t;

      当我们不用mac地址来赋值时,我们就需要802.115.4的地址来赋值。我们对这128位赋值的时候不是随便赋值。符合IEEE802.15.4标准的设备,在出厂时便有一个IEEE地址,IEEE802.15.4地址共有8字节,我们就把标识符的后八个字节,也就是64位换成这个地址。然后将这个后64位中的第四位反转,也就是赋值0X02的这句代码。
     uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);这个函数主要是为了给标识符赋值前64位,具体的就不分析了。
     说一下处理数据到来时的函数。
     
static void
tcpip_handler(void)
{
  static int seq_id;
  char buf[MAX_PAYLOAD_LEN];

  if(uip_newdata()) {
    ((char *)uip_appdata)[uip_datalen()] = 0;
    PRINTF("Server received: '%s' from ", (char *)uip_appdata);
    PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
    PRINTF("n");

    uip_ipaddr_copy(&server_conn->ripaddr, &UIP_IP_BUF->srcipaddr);
    PRINTF("Responding with message: ");
    sprintf(buf, "Hello from the server! (%d)", ++seq_id);
    PRINTF("%sn", buf);

    uip_udp_packet_send(server_conn, buf, strlen(buf));
    /* Restore server connection to allow data from any node */
    memset(&server_conn->ripaddr, 0, sizeof(server_conn->ripaddr));
  }
}

     第一眼看的时候,发现好多不知道怎么出来的变量,例如uip_appdata,uip_datalen(),uip_newdata(),查看库函数就可以很清楚的知道,uip_newdata()就是代表是否有新的数据到来,uip_appdata直接就是代表到来的数据,uip_datalen()是指到来数据的长度。通过它们的命名也可以猜出来。uip_ipaddr_copy(&server_conn->ripaddr, &UIP_IP_BUF->srcipaddr);这句代码是将客户端的地址赋值到咱们申请的conn中,因为服务器需要回复客户机,因此需要客户机的地址。通过接收到的这个数据找到源端的地址。而#define UIP_IP_BUF   ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])这句可以知道UIP_IP_BUF  其实代表的是uip_buf,查看库函数可以知道uip_buf就是代表的接收数据的缓存区,当有数据到来的时候就是在这里,但是这个数据不能直接将源端的地址提取出来,因此将其强制转换成uip_ip_hdr格式的数据。这种格式的数据中可以直接得到源端数据。uip_ip_hdr的数据格式为

struct uip_ip_hdr {
#if UIP_CONF_IPV6
  /* IPV6 header */
  uint8_t vtc;
  uint8_t tcflow;
  uint16_t flow;
  uint8_t len[2];
  uint8_t proto, ttl;
  uip_ip6addr_t srcipaddr, destipaddr;
#else /* UIP_CONF_IPV6 */
  /* IPV4 header */
  uint8_t vhl,
    tos,
    len[2],
    ipid[2],
    ipoffset[2],
    ttl,
    proto;
  uint16_t ipchksum;
  uip_ipaddr_t srcipaddr, destipaddr;
#endif /* UIP_CONF_IPV6 */
};
      
可以看到srcipaddr就是源端的地址。


最后

以上就是笨笨酒窝为你收集整理的contiki学习笔记-udp-server.c文件详细的解析的全部内容,希望文章能够帮你解决contiki学习笔记-udp-server.c文件详细的解析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(49)

评论列表共有 0 条评论

立即
投稿
返回
顶部