前面的博文中,不管是做爲client端仍是server端,它們之間的通訊都是經過具體的IP地址來尋址。經過IP地址來尋址,自己就是一個弊端,用戶怎麼會去記住這些魔法數字呢?那麼有沒有辦法能夠經過其餘方式來映射到IP地址,咱們只須要記住有意義的名字呢?
通常來講,咱們遇到問題,不少同窗包括我本身,都很喜歡去baidu或者google,那麼baidu或者google是怎麼映射到IP地址呢?其實,這裏就用到了一種叫作別名的技術,DNS服務。
DNS(Domain Name System,域名系統),因特網上做爲域名和IP地址相互映射的一個分佈式數據庫,可以使用戶更方便的訪問互聯網,而不用去記住可以被機器直接讀取的IP數串。經過主機名,最終獲得該主機名對應的IP地址的過程叫作域名解析(或主機名解析)。html
可是,博主本次講的並非DNS服務,而是以它來引入域名和IP地址相互映射的概念,而且引入本帖子的重點內容 ESP8266mDNS庫。
其中,ESP8266mDNS是採用mDNS協議,跟DNS服務是兩種不一樣的概念,請不要混淆。web
mDNS,便是組播dns(Multicast DNS),mDNS主要實現了在沒有傳統DNS服務器的狀況下使局域網內的主機實現本地發現和域名訪問,使用端口爲5353,聽從dns協議,使用現有的DNS信息結構、名語法和資源記錄類型,而且沒有指定新的操做代碼或者響應代碼。
這裏須要注意幾個點:數據庫
在局域網中,設備和設備之間相互通訊須要知道對方的具體IP地址。而一般狀況下,若是咱們不去設置靜態ip地址,通常都是經過DHCP client動態分配IP地址,這個時候若是沒有可視化界面去查看,通常咱們是沒法得知具體的IP地址,咱們也就沒法與之通訊。這個時候,就是mDNS大顯神威的時候,咱們經過具體的名字去訪問就好。服務器
mdns 使用組播地址爲: 224.0.0.251 (ipv6: FF02::FB) 端口爲5353,mdns 是用於局域網內部的,而且主機的域名爲.local 結尾;網絡
每一個進入局域網的主機,若是開啓了mDNS服務的話,都會向局域網內的全部主機組播一個消息,我是誰,和個人IP地址是多少。而後其餘也開啓了mDNS服務的主機就會響應,也會告訴你,它是誰,它的IP地址是多少。固然,具體實現要比這個複雜點。
好比,A主機進入局域網,開啓了 mDNS 服務,並向 mDNS 服務註冊如下信息:我提供 FTP 服務,個人IP是 192.168.1.101,端口是 21。當B主機進入局域網,並向 B 主機的 mDNS 服務請求,我要找局域網內 FTP 服務器,B主機的 mDNS 就會去局域網內向其餘的 mDNS 詢問,而且最終告訴你,有一個IP地址爲 192.168.1.101,端口號是 21 的主機,也就是 A 主機提供 FTP 服務,因此 B 主機就知道了 A 主機的 IP 地址和端口號了。
大概的原理就是這樣子,mDNS提供的服務要遠遠多於這個,固然服務多但並不複雜。app
在前面,咱們說到開啓了mDNS服務的主機在進入局域網後,會向局域網內的全部主機組播一個消息,我是誰,個人IP地址是多少,而後其餘也開啓了mDNS服務的主機也會響應告訴你它是誰,ip地址是多少。在ESP8266mDNS庫中,除了前面的mDNSResponder功能外,還包括了mDNS-SD(服務註冊,服務查詢,服務解析)功能,經過方法能夠獲取到局域網內具體的服務信息。
舉個例子:在局域網內,要進行打印服務,必需要先知道打印服務器的IP地址。此IP地址通常由IT部門人員負責分配,而後他還得全公司發郵件來通知各個部門人員該IP地址。有了mDNS-SD服務,打印服務器註冊一個打印服務,名爲「print service」之類的。當有人須要打印服務時,通常會先搜索局域網的打印服務器。可是因爲不知道打印服務器的IP地址,用戶只能經過諸如「print service」的名字去查找打印機,在mDNS-SD的幫助下,用戶最終能找到註冊了「print service」名字的打印機,並得到它的IP地址以及端口號。tcp
注意點:分佈式
ESP8266使用mDNS服務,請在代碼中加入如下頭文件:函數
#include <ESP8266mDNS.h>
mDNS用到了ESP8266mDNS庫,因此接下來咱們來了解一下這個庫。使用這個庫的時候ESP8266能夠在AP模式或是以STA模式接入局域網。局域網中的其餘開啓mDNS服務的設備就能夠經過網址訪問ESP8266了;oop
因此你們基本上能夠放心使用mDNS服務,基本上的大平臺都支持了。
老規矩,先上一個博主總結的百度腦圖:
整體上,根據功能能夠把方法分爲2大類:
函數說明:
/** * 啓動mDNS服務 * @param hostName const char* (與IP地址映射的域名) * @return bool 是否啓動成功 */ bool begin(const char* hostName);
函數說明:
/** * 通知AP改變 */ void notifyAPChange();
函數說明:
/** * 註冊服務 * @param service 服務名字 * @param proto 服務協議 * @param port 服務端口 */ void addService(char *service, char *proto, uint16_t port); void addService(const char *service, const char *proto, uint16_t port);
函數說明:
/** * 查詢服務 * @param service 服務名字 * @param proto 服務協議 * @return count 返回符合條件的服務個數 */ int queryService(char *service, char *proto); int queryService(const char *service, const char *proto); int queryService(String service, String proto);
函數說明:
/** * 返回服務域名 * @param idx 服務索引 */ String hostname(int idx);
函數說明:
/** * 返回服務IP地址 * @param idx 服務索引 */ IPAddress IP(int idx);
函數說明:
/** * 返回服務端口 * @param idx 服務索引 */ uint16_t port(int idx);
實例說明:
演示ESP8266 mDNS responder功能,燒錄如下代碼到NodeMcu,而後在電腦端輸入如下地址:
http://esp8266.local/
以域名方式來訪問webserver。
實例準備:
實例源碼:
/** * Demo: * 演示ESP8266 mDNS responder功能 * @author 單片機菜鳥 * @date 2019/01/28 */ #include <ESP8266WiFi.h> #include <ESP8266mDNS.h> #include <ESP8266WebServer.h> //如下三個定義爲調試定義 #define DebugBegin(baud_rate) Serial.begin(baud_rate) #define DebugPrintln(message) Serial.println(message) #define DebugPrint(message) Serial.print(message) const char* AP_SSID = "TP-LINK_5344"; // XXXXXX -- 使用時請修改成當前你的 wifi ssid const char* AP_PSK = "6206908you11011010"; // XXXXXX -- 使用時請修改成當前你的 wifi 密碼 const unsigned long BAUD_RATE = 115200;// serial connection speed //聲明一下函數 void initBasic(void); void initWifi(void); void initWebServer(void); void initmDNS(void); ESP8266WebServer server(80); /** * 處理根目錄uri請求 * uri:http://server_ip/ */ void handleRoot() { DebugPrintln("handleRoot"); server.send(200, "text/html", "Hello From ESP8266 mDNS demo"); } /** * 處理無效uri * uri:http://server_ip/xxxx */ void handleNotFound() { DebugPrintln("handleNotFound"); //打印無效uri的信息 包括請求方式 請求參數 String message = "File Not Found\n\n"; message += "URI: "; message += server.uri(); message += "\nMethod: "; message += (server.method() == HTTP_GET) ? "GET" : "POST"; message += "\nArguments: "; message += server.args(); message += "\n"; for (uint8_t i = 0; i < server.args(); i++) { message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; } server.send(404, "text/plain", message); } void setup(void) { initBasic(); initWifi(); initWebServer(); initmDNS(); } void loop(void) { server.handleClient(); } /** * 初始化基礎功能:波特率 */ void initBasic(){ DebugBegin(BAUD_RATE); } /** * 初始化wifi模塊:工做模式 鏈接網絡 */ void initWifi(){ WiFi.mode(WIFI_STA); WiFi.begin(AP_SSID, AP_PSK); DebugPrintln(""); // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(500); DebugPrint("."); } DebugPrintln(""); DebugPrint("Connected to "); DebugPrintln(AP_SSID); DebugPrint("IP address: "); DebugPrintln(WiFi.localIP()); } /** * 初始化webserver */ void initWebServer(){ //如下配置uri對應的handler server.on("/", handleRoot); server.on("/inline", []() { DebugPrintln("handleInline"); server.send(200, "text/plain", "this works as well"); }); server.onNotFound(handleNotFound); //啓動webserver server.begin(); DebugPrintln("HTTP server started"); } /** * 初始化mDNS */ void initmDNS(){ if (!MDNS.begin("esp8266")) { DebugPrintln("Error setting up MDNS responder!"); while (1) { delay(1000); } } DebugPrintln("mDNS responder started,please input http://esp8266.local/ in your browser after install Bonjour"); }
實例結果:
實例說明:
演示ESP8266 mDNS 發現服務功能,分別燒錄代碼到兩塊NodeMcu。
實例準備:
實例源碼:
/* 演示ESP8266 mDNS 發現服務功能 注意: - 輸入你的 WiFi SSID 和 password. - 燒寫到兩塊 ESP8266 板子 */ #include <ESP8266WiFi.h> #include <ESP8266mDNS.h> const char* ssid = "..."; const char* password = "..."; char hostString[16] = {0}; void setup() { Serial.begin(115200); delay(100); Serial.println("\r\nsetup()"); sprintf(hostString, "ESP_%06X", ESP.getChipId()); Serial.print("Hostname: "); Serial.println(hostString); WiFi.hostname(hostString); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(250); Serial.print("."); } Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); if (!MDNS.begin(hostString)) { Serial.println("Error setting up MDNS responder!"); } Serial.println("mDNS responder started"); //往mDNS裏面註冊服務 MDNS.addService("esp", "tcp", 8080); Serial.println("Sending mDNS query"); //查找服務 int n = MDNS.queryService("esp", "tcp"); // Send out query for esp tcp services Serial.println("mDNS query done"); if (n == 0) { Serial.println("no services found"); } else { Serial.print(n); Serial.println(" service(s) found"); for (int i = 0; i < n; ++i) { // 打印查找到的服務具體信息 Serial.print(i + 1); Serial.print(": "); Serial.print(MDNS.hostname(i)); Serial.print(" ("); Serial.print(MDNS.IP(i)); Serial.print(":"); Serial.print(MDNS.port(i)); Serial.println(")"); } } Serial.println(); Serial.println("loop() next"); } void loop() { // put your main code here, to run repeatedly: }
本節主要講解mDNS在8266上的域名映射應用,總體上內容很少,可是是一個很是有用的知識點,但願讀者能仔細學習。而且能夠的話,回顧一下如下兩個篇章: