概述
上文中已经将大部分的复杂的用到的函数给解释了一下。刚刚看了一下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文件详细的解析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复