關(guān)于零配置網(wǎng)絡(luò)
任何一個設(shè)備要接入網(wǎng)絡(luò)中憔四,必須得有IP地址膀息、子網(wǎng)掩碼、網(wǎng)關(guān)IP地址等信息了赵。嵌入式設(shè)備為了方便生產(chǎn)潜支,一般會將這些信息都固定,在設(shè)備運行前再根據(jù)具體環(huán)境對設(shè)備進行配置斟览,靈活性大大降低毁腿,體驗更是渣到不行辑奈。而蘋果設(shè)備易用性的其中一點體現(xiàn)就是苛茂,當設(shè)備接入一個網(wǎng)絡(luò)時,不需要做任何的配置鸠窗,就可以訪問妓羊。
那蘋果設(shè)備是如何做到的?
原因就是蘋果的設(shè)備都使用一項名為Bonjour的技術(shù)稍计。這個名字裝過iTunes的土豪應該都見過躁绸,iTunes附帶這個組建,因此裝上iTunes的PC也可以很方便的訪問蘋果設(shè)備了臣嚣。
Bonjour是零配置網(wǎng)絡(luò)的一個實現(xiàn)净刮,是開源的哦,另一個開源的實現(xiàn)叫avahi硅则。零配置網(wǎng)絡(luò)淹父,英文全稱Zero Configuration Networking,簡稱Zeroconf怎虫。實現(xiàn)零配置網(wǎng)絡(luò)需要做到以下幾點:
Allocate addresses without a DHCP server
在傳統(tǒng)網(wǎng)絡(luò)環(huán)境下暑认,設(shè)備的IP地址通過兩種方式獲取,一種是靜態(tài)配置大审,通過手工方式為設(shè)備指定一個IP地址蘸际,一種是動態(tài)配置,設(shè)備通過DHCP服務器獲得動態(tài)的IP地址徒扶。在有DHCP服務器的網(wǎng)絡(luò)下粮彤,自然可以免除配置,但是在無中心服務器的網(wǎng)絡(luò)環(huán)境下,無法提供DHCP服務导坟,這時候如何解決自動獲取IP的問題缠诅?
在IPV6環(huán)境下,IPV6協(xié)議本身就提供了設(shè)備自指定IP地址的能力乍迄,所以是直接支持了管引。
在IPV4環(huán)境下,可以使用鏈路本地地址(Link-local address)闯两。Translate between names and IP addresses without a DNS server
在傳統(tǒng)網(wǎng)絡(luò)環(huán)境下褥伴,名稱和IP地址的對應關(guān)系是通過DNS服務解析的。在沒有中心服務器的網(wǎng)絡(luò)環(huán)境中漾狼,沒有DNS服務器提供域名解析服務重慢,這時候又該如何解決名稱解析的問題?
Bonjour使用的是叫mDNS的解決方案逊躁,mDNS——全稱Multicast DNS似踱。Find services without a directory server
在前面,自動獲取IP和名字轉(zhuǎn)IP的問題都解決了稽煤。但是還是沒能實現(xiàn)一個零配置的網(wǎng)絡(luò)核芽,因為我不知道設(shè)備提供了什么服務,還得手動去配置酵熙。所以轧简,最后要解決的就是如何知道網(wǎng)絡(luò)中的設(shè)備提供了哪些服務!X叶哮独!
解決方案是DNS Service Discovery (DNS-SD)。
前面提到了兩個開源的實現(xiàn)察藐,都滿足了上述3點皮璧。其中Bonjour有在MT7687上的移植,在SDK中可以找到分飞,沒看懂多少……………………
還好悴务,lwIP 2.xx版本提供了mDNS,真的省了不少事浸须。
lwIP提供的mDNS
首先要注意的是惨寿,lwIP(V2.1.2)提供的mDNS沒有完全實現(xiàn)規(guī)范中的所有特性!I局稀裂垦!
下面是沒有實現(xiàn)的特性:
- Tiebreaking for simultaneous probing
- Sending goodbye messages (zero ttl) - shutdown, DHCP lease about to expire, DHCP turned off...
- Checking that source address of unicast requests are on the same network
- Limiting multicast responses to 1 per second per resource record
- Fragmenting replies if required
- Handling multi-packet known answers
- Individual known answer detection for all local IPv6 addresses
- Dynamic size of outgoing packet
雖然沒有完全實現(xiàn)規(guī)范中的特性,但是看了下V2.1.2以來的更新日志肌索,對MDNS有不少優(yōu)化的地方蕉拢,后面應該會更完善的。
使用前準備
1、在lwipopts.h
設(shè)置LWIP_MDNS_RESPONDER = 1
晕换,使能這個特性;
2午乓、定義單個網(wǎng)卡能提供的最大服務個數(shù),MDNS_MAX_SERVICES
闸准,默認值是1
益愈;
3、MDNS需要一個PCB
夷家,所以MEMP_NUM_UDP_PCB
增加1蒸其;
4、MDNS在網(wǎng)卡需要個入口點库快,所以LWIP_NUM_NETIF_CLIENT_DATA
增加1摸袁;
5、IPv4下需要設(shè)置LWIP_IGMP = 1
义屏,最好也設(shè)置LWIP_AUTOIP = 1
靠汁;IPv6下需要設(shè)置LWIP_IPV6_MLD = 1
;(MDNS支持在IPv4 only, v6 only, 和 v4+v6下使用)
6闽铐、為了減少動態(tài)內(nèi)存分配蝶怔,MDNS代碼的運行塊放在堆中,最多可能使用1K的大醒羯丁添谊;
MDNS的使用
注意:LWIP_AUTOIP只有在網(wǎng)絡(luò)中不存在DHCP Server時才起作用,為了適配兩種場景察迟,配置同時支持DHCP
和AUTOIP
!6摺扎瓶!
/*
------------------------------------
---------- AUTOIP options ----------
------------------------------------
*/
#define LWIP_DHCP 1
#define LWIP_AUTOIP 1
#define LWIP_DHCP_AUTOIP_COOP 1
#define LWIP_DHCP_AUTOIP_COOP_TRIES 5 // 默認是9,調(diào)小可以在DHCP失敗后更快的切換到AutoIP
/*
---------------------------------
---------- MDNS options ----------
---------------------------------
*/
#define LWIP_MDNS_RESPONDER 1
#define MDNS_MAX_SERVICES 1
#define LWIP_NUM_NETIF_CLIENT_DATA 1
/* Announce IP settings have changed on netif. Call this in your callback registered by [netif_set_status_callback()](group__netif.html#gadc8787b23ac0ee023979cbadf87813d4). No need to call this function when LWIP_NETIF_EXT_STATUS_CALLBACK==1, this handled automatically for you.
*/
#define LWIP_NETIF_EXT_STATUS_CALLBACK 1
直接上代碼
const char hostname[] = "NUC472HI8AE";
static void srv_txt(struct mdns_service *service, void *txt_userdata)
{
err_enum_t res;
res = mdns_resp_add_service_txtitem(service, "path=/", 6);
LWIP_ERROR("mdns add service txt failed\n", (res == ERR_OK), return);
}
static void vWebTask( void *pvParameters )
{
tcpip_init(NULL, NULL);
netif_add(&netif, NULL, NULL, NULL, 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);
#if LWIP_DHCP
err_t err;
err = dhcp_start(&netif);
if (err == ERR_OK)
log_i("lwip dhcp init success...\n\n");
else
log_e("lwip dhcp init fail...\n\n");
#endif
http_server_netconn_init();
mdns_resp_init();
mdns_resp_add_netif(&netif, hostname, 3600);
mdns_resp_add_service(&netif, "myweb", "_http", DNSSD_PROTO_TCP, 80, 3600, srv_txt, NULL);
vTaskSuspend( NULL );
}
編譯后下載到板子運行泌枪,從下圖可以看到概荷,192.168.1.159這個地址提供了一個http服務訪問該服務
嘗試在windows 7下用chrome訪問NUC472HI8AE.local:80
修壕,不成功愈捅,在ubuntu上用firefox倒是成功了,可能是windows 7不支持mdns的原因慈鸠。
遺憾
V2.1.2版本沒有提供服務搜尋接口蓝谨,所以無法在設(shè)備上去主動搜尋網(wǎng)絡(luò)中的服務,下一版會解決這個,只能期待快點發(fā)布了譬巫。