如何用W7100A实现DDNS客户端(二)

大家好,前面我们为大家分享了如何用W7100A实现DDNS客户端(一),即DDNS规格和DDNS演示,今天继续为大家分享后面一部分即代码演示,希望对大家有帮助~

第一部分请参考:http://blog.csdn.net/wiznet2012/article/details/7694968

 

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; x<4; x++)

{

        //将字符串分割成一个整数数组

        if(x == 0)

               split = strtok(tmp_str,”.”);

        else

        {

               split = strtok(NULL,”.”);

        }

        dns_ip[x] = atoi(split);

        //检测IP是否有效

        if(dns_ip[x] >255 || dns_ip[x] < 0)

        {

               //检测到无效的IP,重新输入IP地址

               goto start;

        }

}

// 打印 DNS IP地址

// 输入网络服务器新的IP地址并且检测IP地址是否有效(与上面相同的代码)

//打印网络服务器的IP地址

4.1.2 对比新旧IP地址

DDNS程序将读取上次更新时保存在闪存中的IP地址。然后,进行比较来决定是否需要更新。

 

for(x = 0; x<4; x++)

        {

                    //从闪存中读取之前更新的IP地址

               flash_ip[x] = 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] == 0 &&  dyndns_ip[1] == 0 && dyndns_ip[2] == 0 && dyndns_ip[3] == 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=%s&myip=%s&wildcard=NOCHG&mx=NOCHG&backm 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 [64] = {  ‘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[100] = {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[out_idx]    = (usrpwd[in_idx]&0xFC) >>  2;

base64_userpwd[out_idx]  =     encodingTable[tmp[out_idx]];

//提取下一个6位并且插入到编码表中

tmp[out_idx  + 1]      = (((usrpwd[in_idx]&0x03)  <<4) | ((usrpwd[in_idx+1]&0xF0)>>4));

base64_userpwd[out_idx  + 1] =       encodingTable[tmp[out_idx +  1]];

//提取下一个6位并且插入到编码表中

tmp[out_idx  + 2]      =  (((usrpwd[in_idx+1]&0x0F) <<2) | ((usrpwd[in_idx+2]&0xC0)>>6));

base64_userpwd[out_idx  + 2] =       encodingTable[tmp[out_idx +  2]];

//提权下一个6位并且插入到编码表中

tmp[out_idx  + 3]      = (usrpwd[in_idx+2]&0x3F);

base64_userpwd[out_idx  + 3] =       encodingTablse[tmp[out_idx  + 3]];

//最后4位的特殊情况应用

if(remaining  == 4)

{

switch(num)

        {

        case  1: // 添加字符 ‘==’到空白编译好的字符串                            memcpy(base64_userpwd+out_idx  + 2,”==”,2);

        break;

       case 2: // 添加一个 ‘=’字符到空白编译好的字符串

        tmp[out_idx  + 2]      =  (((usrpwd[in_idx+1]&0x0F) <<2) |  ((usrpwd[in_idx+2]&0xC0)>>6));

        base64_userpwd[out_idx  + 2] =       encodingTable[tmp[out_idx +  2]];                         memcpy(base64_userpwd+out_idx  + 3,”=”,1);

        break;

        default:

        break;

       }

}

       out_idx += 4;    // 索引递增

        in_idx  += 3;           //索引递增

       remaining -= 4;      //剩余字符串计数器递减

}

}

更多有关W7100的博文请看这里:

W7100例程学习之ADC应用http://blog.iwiznet.cn/?p=691

用W7100,做自己的HTTP服务器 http://blog.iwiznet.cn/?p=684

W7100学习笔记 -W7100部分固件(firmware)解析http://blog.iwiznet.cn/?p=677

什么是API函数以及如何使用W7100A进行初始化(TCPIPCore)?(二)http://blog.iwiznet.cn/?p=628

更多有关W7100A的博文请看这里:

如何使用W7100A实现网络字符LCD  http://blog.iwiznet.cn/?p=168

单片机以太网控制芯片— iMCU W7100A http://blog.iwiznet.cn/?p=229

如何使用W7100A模拟I2C总线 http://blog.iwiznet.cn/?p=304

如何实现W7100A程序烧录 http://blog.iwiznet.cn/?p=161