不记得从什么时候开始了,路由器越来越多的通过域名来访问配置页面,而不是像之前那样输入一串难记的IP地址来访问。个人认为这种体验相当好,下面通过在lwip 2.1.2中httpserver
例子的基础上实现一样的效果来看其中的实现方法。
原理
学过计算机网络的同学都知道通过域名访问某个网站,需要先经过域名解析(DNS)服务将域名解析成IP地址,然后再通过IP去访问这个网站。由此可知,要实现通过域名去访问板子上的HTTP server,只需要保证域名解析(DNS)服务能将我们的域名(暂定为www.my_board.com)解析成IP地址(192.168.1.2
)即可。
DNS 查询的过程如下:
- 在浏览器中输入http://www.baidu.com域名,计算机会先检查自己本地的hosts文件、本地DNS解析器缓存是否有这个网址映射关系,如果有则直接返回,完成域名解析。
- 如果hosts与本地DNS解析器缓存都没有相应的网址映射关系,会通过TCP/IP参数中设置的首选DNS服务器进行查询,如果该服务器具有网址映射关系,则调用这个IP地址映射,完成域名解析。
- 当以上的DNS服务器和缓存解析都失效了,则会将请求转发至上一级DNS服务器或根DNS进行解析,以此循环。该过程属于DNS服务器之间的交互查询。
更详细的DNS说明可以在这篇文章查看。
实现
首先我们需要一个dns服务器,那就在板子上实现一个超简单DNS server,通过这个服务器完成域名解析。LwIP没有提供DNS server的实现,我在github上找了一个(戳这里去看看),并做了一些修改。
代码中的这些DNS相关的参数在这篇文章有解释
/* dns_server.h */
#ifndef __DNA_SERVER_H__
#define __DNA_SERVER_H__
#define SIZEOF_DNSANS_HDR 12
#define SIZEOF_DNSANS_HDRQUE 20
#define DNS_SERVER_ID 0x0000
#define DNS_SERVER_FLAGS 0x8180
#define DNS_SERVER_NUMQUE 0x0001
#define DNS_SERVER_ANSRRS 0x0001
#define DNS_SERVER_AUTRRS 0x0000
#define DNS_SERVER_ADDRRS 0x0000
#define TABLENAME "www.my_board.com" // 待解析的域名
#define DNS_SERVER_TYPE 0x0001
#define DNS_SERVER_CLASS 0x0001
#define DNS_POINAME 0xC00C
#define DNS_SERVER_ANSTYPE 0x0001
#define DNS_SERVER_ANSTYPEE 0x0001
#define DNS_SERVER_DATALEN 0x0000
#define DNS_SERVER_ANSTIME 0x003c0004 // 这里要注意,003c和前面DATALEN的0000一起组成0000003c,作为生存时间,后面的0004才是真的DATALEN
#define DNS_SERVER_ADRESS 0xc0a80102 // 解析返回的IP,这里是192.168.1.2
void dns_server_send(void);
void get_dns_request(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, uint16_t port);
void dns_server_init(void);
#endif
到此,DNS服务器就配置完了,但是浏览器怎么知道这个服务器的地址并向这个地址查询域名的IP地址?
这时候需要一个方法来告诉浏览器,DNS服务器的地址,DHCP服务正好提供了这个机制。DHCP server的资料可以看看DHCP详解,在Option字段可以看到DNS Server。
LwIP官方没有实现DHCP server,但是好在rt-thread有实现,到这里下载即可。将文件加入工程后,在lwipopts.h
中增加如下配置
/**
* DHCP server setting
*/
#define DHCPD_CLIENT_IP_MAX 2 // 只有开发板和PC直连,所以分两个绰绰有余了
#define DHCPD_SERVER_IP "192.168.1.1" // 设置好DHCP server的地址
初始化代码如下
static void vWebTask( void *pvParameters )
{
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gw;
tcpip_init(NULL, NULL);
IP4_ADDR(&gw, 192,168,1,1);
IP4_ADDR(&ipaddr, 192,168,1,1);
IP4_ADDR(&netmask, 255,255,255,0);
netif_add(&netif, &ipaddr, &netmask, &gw, NULL, ethernetif_init, tcpip_input);
netif_set_default(&netif);
if (netif_is_link_up(&netif))
{
/* When the netif is fully configured this function must be called */
netif_set_up(&netif);
}
else
{
/* When the netif link is down this function must be called */
netif_set_down(&netif);
}
NVIC_SetPriority(EMAC_TX_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
NVIC_EnableIRQ(EMAC_TX_IRQn);
NVIC_SetPriority(EMAC_RX_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
NVIC_EnableIRQ(EMAC_RX_IRQn);
ip_addr_t ip_start_addr;
ip_addr_t ip_end_addr;
IP4_ADDR(&ip_start_addr, 192,168,1,2);
IP4_ADDR(&ip_end_addr, 192,168,1,254);
dhcp_server_start(&netif, &ip_start_addr, &ip_end_addr);
http_server_netconn_init();
vTaskSuspend( NULL );
}
下载到板子上,在浏览器中输入域名,访问成功!