热度 18
2012-6-28 09:56
1070 次阅读|
0 个评论
大家好,前面我们为大家分享了如何用W7100A实现DDNS客户端(一),即DDNS规格和DDNS演示,今天继续为大家分享后面一部分即代码演示,希望对大家有帮助~ 第一部分请参考: http://bbs.ednchina.com/BLOG_ARTICLE_3005238.HTM 4. 代码演示 这一章节将会介绍在 DDNS 协议中用到的所有代码。这些代码保存在 DDNS.c 和 DDNS.h 中。为了能够执行 DDNS 的更新,主程序必须调用 DDNS_update() 函数。 DDNS_update() 函数按照下面的流程图: 尽管 DDNS 是一个很简单的请求和响应协议,仍然需要很多步骤准备 DDNS 请求信息。下面的章节介绍 DDNS 协议的所有的不同的阶段。 4.1 DDNS_Update()函数 4.1.1 检索用户输入 在这一部分的代码中, 将会检索ISP提供的用户DNS地址以及网络服务器的新的IP地址。 start: // 输入 ISP’s DNS IP 地址 for(x = 0; x4; x++) { // 将字符串分割成一个整数数组 if(x == 0) split = strtok(tmp_str,"."); else { split = strtok(NULL,"."); } dns_ip = atoi(split); // 检测 IP 是否有效 if(dns_ip 255 || dns_ip 0) { // 检测到无效的 IP ,重新输入 IP 地址 goto start; } } // 打印 DNS IP 地址 // 输入网络服务器新的 IP 地址并且检测 IP 地址是否有效 ( 与上面相同的代码 ) // 打印网络服务器的 IP 地址 4.1.2 对比新旧IP地址 DDNS 程序将读取上次更新时保存在闪存中的 IP 地址。然后,进行比较来决定是否需要更新。 for(x = 0; x4; x++) { // 从闪存中读取之前更新的IP 地址 flash_ip = EEP_Read(x); } // 比较之前的 IP 地址和当前的 IP 地址 if(memcmp(flash_ip,current_ip,4)==0) { // 检测到相同的 IP 地址,通知用户并且离开 goto exit; // 退出程序 } // 继续 DDNS 协议 4.1.3 执行DNS查询并且连接到服务器 DNS 查询请求从 DDNS 服务器主机名上查找实际的 IP 地址。在找到 IP 地址后,程序会连接到服务器。更多关于 dns_query() 函数的详细信息,请参阅文档“如何用 W7100A 实现 DNS 客户端”。 dns_query(s,"members.dyndns.org"); // 用 DNS 查询找到 members.dyndns.org 的 IP 地址 // 去确认我们是否 从DNS 查询获得IP地址 if( dyndns_ip == 0 dyndns_ip == 0 dyndns_ip == 0 dyndns_ip == 0) { // 从主机名获取IP 地址失败 goto start; // 请求用户重新输入 DNS IP 地址信息 } // 使用 loop 循环来发送请求并且接收来自服务器的响应 switch(getSn_SR(s)) // 确认 socket 状态 { case SOCK_CLOSED: port++; if(socket(s,Sn_MR_TCP, port, 0x00) == 1) // 打开 TCP 模式下的 Socket { // 创建 socket 成功 sent_flag = 0; } else { // 创建socket 失败 close(s); } break; case SOCK_INIT: if(connect(s,dyndns_ip,80) == 1) // 连接到 DynDNS 服务器 { // 成功连接到服务器并且打印连接的 IP 地址 } else { // 连接服务器失败 } break; 4.1.4 发送请求信息 Base64_encode() 将用户名和密码字符串转换成一个 base64 编码格式。在用户名和密码字符串编译完成后, HTTP GET 请求信息也已经准备就绪。请确保在每一个 \r\n 之后没有空格,否则请求信息将不会被认为是 http 数据包。请求信息成功发送后,程序将等待服务器的回应。 case SOCK_ESTABLISHED: // 将用户名和密码编译成base64 base64_encode(user_pass,base64_user_pass,strlen(user_pass)); // 创建 HTTP HET 请求信息 sprintf(request_msg,"GET/nic/update?hostname=%smyip=%swildcard=NOCHGmx=NOCHGbackm x=NOCHG HTTP/1.1 \r\nHost: members.dyndns.org \r\nAuthorization: Basic %s \r\nUser-Agent:%s \r\n\r\n",host_name ,ip_addr_str ,base64_user_pass,user_agent); // 发送请求信息 send(s,request_msg,strlen(request_msg)); // 确认接收缓存器中是否有数据 len = getSn_RX_RSR(s); if (len 0) { // 确认接收到的数据长度是否比缓存器空间大 if(len MAX_LENGTH) len = MAX_LENGTH; len = recv(s, reply_msg, len); // 将数据存放到reply_msg } break; 4.1.5 解析应答信息 程序检查回复信息并且打印出结果。 // 在回复串中搜索更新成功 split = strstr(reply_msg,"good"); if(split != NULL) { // 更新来自回复信息的解析数据成功 split_end = strstr(split,"\r\n0\r\n\r\n"); len = split_end - split; // 将最新的IP 地址写入闪存 EEP_Block_Write(0,current_ip, 4); // 打印 回应 信息 } else { // 更新来自回复信息中的失败解析数据 split = strstr(reply_msg,"\r\n\r\n"); split = strstr(split+4,"\r\n"); split += 2; split_end = strstr(split,"\r\n0\r\n\r\n"); len = split_end - split; // 打印 回应 信息 } 4.1.6 Base64编码 base64_encode() 函数使用一个编码表将字符串转换成 base64 格式。例如,如果编码字符‘ a ’,结果将会是“ YQ== ”。字符‘ a ’有 8 位(“ 01100001 ”)。提出前 6 位(“ 011000 ”)并且插入到编码表输出‘ Y ’。同样的过程应用到最后两位(“ 010000 ”)。注意最后这两位要移动到第一和第二的位置。在插入完成之后,结果为‘ Q ’。请注意编码函数通常以 4 的倍数输出字符。结果,对于空白字符,将会添加“ == ”到编译好的字符串。 Void base64_encode(uint8* usrpwd,uint8* base64_userpwd,int len) { // 编码表 static char xdata encodingTable = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'}; uint8 xdata in_idx = 0; // 输入缓存索引 uint8 xdata out_idx = 0; // 输出缓存索引 uint8 xdata remaining = 0; // 剩余待处理的字符串 uint8 xdata num = 0; // 待处理的字符串数目 uint8 xdata tmp = {0,}; // tmp 字符串 num = (len%3); // 确定有多少个字符串 if(num == 0) { remaining = len + (len/3); // 计算编码字符串的长度 } else { switch(num) { case 1: remaining = ((len *4)/3)+ 3; // 计算编码字符串的长度 break; case 2: remaining = ((len *4)/3)+ 2; // 计算编码字符串的长度 break; default: break; } } while(remaining 0) { // 提取前 6 位并且插入到编码表中 tmp = (usrpwd 0xFC) 2; base64_userpwd = encodingTable ]; // 提取下一个 6 位并且插入到编码表中 tmp = (((usrpwd 0x03) 4) | ((usrpwd 0xF0)4)); base64_userpwd = encodingTable ]; // 提取下一个 6 位并且插入到编码表中 tmp = (((usrpwd 0x0F) 2) | ((usrpwd 0xC0)6)); base64_userpwd = encodingTable ]; // 提权下一个 6 位并且插入到编码表中 tmp = (usrpwd 0x3F); base64_userpwd = encodingTablse ]; // 最后 4 位的特殊情况应用 if(remaining == 4) { switch(num) { case 1: // 添加字符 ‘==’ 到空白编译好的字符串 memcpy(base64_userpwd+out_idx + 2,"==",2); break; case 2: // 添加一个 ‘=’ 字符到空白编译好的字符串 tmp = (((usrpwd 0x0F) 2) | ((usrpwd 0xC0)6)); base64_userpwd = encodingTable ]; memcpy(base64_userpwd+out_idx + 3,"=",1); break; default: break; } } out_idx += 4; // 索引递增 in_idx += 3; // 索引递增 remaining -= 4; // 剩余字符串计数器递减 } }