在網路通訊的世界裡,最基本就是兩個角色,一個是提出請求的客戶端(Client),另一邊則是回應需求的伺服器(Server)端,至於其他的網路設備,如路由器(Router)、集線器(Hub)、通訊閘道(Gateway)、中繼器(Repeater)...等,都只是為了要讓這兩種裝置能順利地連接在一起,達成網路通訊的目的而已。ESP8266這個晶片模組可分別執行客戶端(Client)與伺服器(Server)端這兩個腳色,可以連上網際網路,亦可自行組成一個區域性的無線WiFi網路,如果要在這個無線WiFi區域網路擔任伺服器(Server)個腳色時,就必須扮演無線WiFi網路中的存取點(AP:Access Point)功能了!
所謂的網路伺服器(WebServer),是指一種連接在網路上的設備,這種設備主要用於儲存和提供數據/文件,而客戶端(Client)這種裝置可以請求這些文件或其他數據,網路伺服器將此請求(request)解譯之後,再將正確的數據/文件發送回客戶端。一般來說這兩種設備之間使用所謂的HTTP通訊協定來進行需求與資料的雙向傳輸,所謂的HTTP(Hypertext Transfer potocal)或超文本傳輸協定,是用於與(Web)伺服器通信的基於文本的協定,HTTP請求方法有多種,但由於ESP8266只是一顆內部資源有限的單晶片微電腦而已,所以我們只會介紹兩種最常用的方法也就是:GET和POST。
在HTTP通訊協定中,GET這種請求用於從伺服器檢索數據/文件,例如瀏覽器連接網頁;它只是單純從伺服器獲取數據/文件,不會要求或試著更改伺服器內部的資料,因此沒有其他的副作用。當我們使用瀏覽器中打開某一個網頁時,它將獲取URL並將其放入HTTP GET請求中,這只是純文本(plain text)資料,然後它將使用TCP通訊協定將請求發送到正確的伺服器;伺服器讀取請求後,檢查URL,並將該URL的正確HTTP響應發送回瀏覽器。
六、3-1 GET請求的解析
在HTTP 的GET請求中最重要的部分是請求行(request Line)和主機檔頭(host header),接下來我們以一個範例來說明:
請啟動你電腦的瀏覽器(在此使用的是Google Chrome,其他的瀏覽器也可以,當然你的電腦必須已經連上網際網路),接著在URL列輸入以下鏈接網址:
這時您的瀏覽器將發出以下HTTP請求:
圖六、4 瀏覽器連接http://www.example.com網站後的內容
在【圖六、4】中標記1是我們要前往網頁的URL網址,這是一個網路上有名的樣本網站,的內容就是左邊標記2簡單的文字說明;不過要看到右邊相關的資訊,請在連上這個網站之後按下電腦鍵盤的[F12]功能鍵,然後依序點擊的標記3重新載入按鈕再次的載入網頁,接著是標記4的[ Network ]標籤、標記5的網站名稱[www.example.com]、標記7的解析(parsed)選項後,便可以完整的看到標記6與8的內容了。
所謂的請求行主要包括兩個部份,分別是URI(Uniform Resource Identifier)也就是請求的內容,再來就是請求的方式「GET」;至於主機檔頭,則是要連接的主機伺服器(host server)的網域名稱。在標記6的區域中我們可看到前兩行的內容為:
Request URL:http://www.example.com/
Request Method:GET
第二行的內容就是請求的方式「GET」,而第一行的內容其實是由兩個部分所構成,分別是代表主機檔頭的主機伺服器(host server)網域名稱:[http://www.example.com],及請求的內容:「’/’」,這個內容也就是一般網站主網頁的意思。
接下來我們就以一個範例程式來看看,當我們用手機或平板電腦的瀏覽器去連接ESP8266的AP存取點伺服器網站時,會送出那些資訊出來:
◎範例程式功能與動作說明:
1、以ESP8266建立一無線WiFi存取點,SSID名稱為『ESP_softAP01』,不 使用密碼。
2、此AP存取點內建伺服器的IP位址為:[ 192.168.0.100 ]。
3、當有客戶端裝置連線上ESP8266時,讀取客戶端(手機、平板或筆電上的瀏覽器)所傳送來的請求訊息,並顯示在電腦上的Arduino IDE序列監控視窗中。
◎程式說明與列表:
程式的2~10行功能與前面範例相同,但是在第12、13行各宣告一個網路伺服器物件與使用的埠號,以及一個客戶端的物件變數:
WiFiServer server(80); // 宣告網路伺服器物件與使用的埠號
WiFiClient client; // 宣告一個客戶端的物件變數
然後在第28行程式初始化的部分(setup())啟動伺服器的功能:
server.begin(); // 啟動伺服器功能
在主迴圈(loop())開始的第35行程式呼叫「server.available()」這個方法函式去監測是否有客戶端裝置連線到本機的伺服器,若無則回頭繼續執行主迴圈:
client=server.available(); // 測試是否有客戶端連接本機伺服器
如果有客戶端裝置連線到伺服器,則40~47行的while()迴圈會把客戶端裝置傳送來的訊息整合打包後,儲存在「requests」這個字串變數上;一般的瀏覽器在結束傳送時,會送出一個空白行,也就是一整行只有一個代表換行的字元”\n”,因此當ESP8266接收到這樣的字串時(45行),便會以”break”的整令結束while()迴圈;至於剩下的程式,會把完整的客戶端請求訊息顯示在電腦上的Arduino IDE序列監控視窗中。
以下是這個範例程式的全文:
// soft AP 範例三: 分析及顯示瀏覽器傳送的資料內容
#include <ESP8266WiFi.h> // 引入ESP8266專用的WiFi函式庫
String softSsid = "ESP_softAP01"; // 設定本機伺服器的SSID名稱
const char* softPassword = "12345678"; // 設定本機AP存取點的密碼為:”12345678”
IPAddress local_IP(192,168,0,100); // 設定新的伺服器IP位址
IPAddress gateway(192,168,0,1); // 設定新的伺服器閘道位址
IPAddress subnet(255,255,255,0); // 設定新的伺服器網路遮罩位址
WiFiServer server(80); // 宣告網路伺服器物件與使用的埠號
WiFiClient client; // 宣告一個客戶端的物件變數
void setup() {
Serial.begin(115200); //
Serial.println();
Serial.print("Setting soft-AP with configuratin... ");
WiFi.softAPConfig(local_IP,gateway,subnet); // 設定新的本地IP位址
boolean result=WiFi.softAP(softSsid); // 以"ESP_softAP01"作為SSID的名稱
if(result==true)
{ // 初始化設定AP存取點成功
Serial.println("soft-AP ready!");
Serial.print("softAP = "); // 在Arduino IDE串列監控視窗中顯示目前
Serial.println(softSsid); // 顯示SSID名稱
Serial.print("softIP = "); // 在Arduino IDE串列監控視窗中顯示目前使用的
Serial.println(WiFi.softAPIP()); // 本地IP位址,在此為[ 192.168.0.100 ]
server.begin(); // 啟動伺服器功能
}
else
Serial.println("soft-AP failed");
}
void loop() {
client=server.available(); // 測試是否有客戶端連接本機伺服器
if(!client)
return; // 若無則返回起點
// 測試到有客戶端裝置連線
String request="",requests="";
while(client.connected()) // 測試客戶端裝置連線是否還在連線狀態
{
request=client.readStringUntil('\r'); // 讀取客戶端送來的單行請求訊息
// Serial.println(request);
requests+=request; // 將讀取到的訊息合併
if(request=="\n") // 測試是否接收到代表整個請求結束的換行字元
break; // 如果是則結束while()迴圈
}
Serial.println("Request end!"); // 在電腦的串列監控視窗顯示客戶端請求結束訊息
Serial.println("");
Serial.println(requests); // 在序列監控視窗顯示客戶端(client)所送來的指令碼資料
}
程式名稱:softAP3_webServer1.ino
◎ 執行結果:
在程式執行之後,我們可在Arduino IDE串列監控視窗中看到【圖六、5】的內容,其中標記1的部分是在程式初始化時所顯示的資訊,包括目前設定的SSID名稱(在此為”ESP_softAP01”),和自行設定的本地IP位址(192.168.0.100),在本例中為了方便連線測試,所以沒有加上連線密碼。
圖六、5 程式啟動初始化後Arduino IDE串列監控視窗之內容
接著按照前面【圖六、2】的方式開啟手機/平板/筆電的WiFi功能,與”ESP_softAP01”的AP存取點連線後,再依【圖六、6】所示啟動瀏覽器,並在網址輸入欄中(標記1)輸入[ 192.168.0.100 ]這個IP位址並前往;由於這個範例程式只是單純的抓取瀏覽器傳送過來的訊息,然後顯示在Arduino IDE串列監控視窗內,並沒有回傳任何請求,所以會在手機瀏覽器的畫面中看到標記2的回應內容,也就是:「 192.168.0.100 未傳送任何資料」!
圖六、6 手機啟動與瀏覽器連接ESP8266的AP存取點伺服器
圖六、7 瀏覽器連線後傳送資料內容
可是當我們再回頭去看Arduino IDE串列監控視窗,會看到如【圖六、7】的新的內容,也就是多了標記2的部分,而這也就是由手機瀏覽器實際傳送過來的資訊,這當中包含了許多訊息,其中標記3的第一行:
GET / HTTP/1.1
就是前面提到的請求行(request Line),其中包括請求的方式「GET」,及請求的內容:「’/’」,而後面的「HTTP/1.1」則是代表目前所使用的HTTP通訊協定版本為1.1版。至於標記3的第二行:
Host:192.168.0.100
則是所謂的主機檔頭(host header),由於我們的程式沒有提供DNS的功能,所以直接以數字IP位址的方式表示目標伺服器的網域名稱。
如果我們在手機瀏覽器的網址輸入欄輸入URL:「 192.168.0.100/test 」這樣的內容送出之後,可看到【圖六、8】的內容,其中紅色框線中的部分就是此次客戶端送來的請求行(request Line),跟前面的差別就是請求的內容由「’/’」 變成「’/test’」,,也就是說只要在網域名稱或是網路IP後面加上一參數,便可將這些訊息當成請求的一部分傳送給目的伺服器,以作為一些延伸應用;我們在後面的範例中會利用這個特性讓使用者可以用手機跟ESP8266做一些互動,例如遙控一些輸出點,或是讀取一些測量資料等。
圖六、8 瀏覽器網址列輸入”192.168.0.100/test”後傳送資料內容
六、3-2 以文本(plain)的方式回應GET請求
前面的範例是一個已讀不回的伺服器程式,這樣的伺服器應該沒有人會喜歡,接下來我們就把它改成當手機瀏覽器連線到它時會回傳:
"ESP8266 AP模式--網路伺服器1"
這樣一段訊息的程式,好讓使用者知道瀏覽器已經連接上伺服器網頁了。
◎ 範例程式功能與動作說明:
1、以ESP8266建立一無線WiFi AP存取點,此AP存取點SSID名稱為『ESP_softAP01』,而且不使用密碼。
2、此AP存取點內建伺服器的IP位址為:[ 192.168.0.100 ]。
3、當有客戶端裝置連線上ESP8266時,會以文本(plain)的格式回應『ESP8266 AP模式--網路伺服器1』這樣的訊息給客戶端(手機、平板或筆電上的瀏覽器),此時客戶端的瀏覽器便可看見這段文字。
◎ 程式說明與列表:
這個範例程式和前面不同的地方首先是新增加了一個函式庫(第4行):
#include <ESP8266WebServer.h>
這個函式庫是專門讓ESP8266在建構網頁伺服器之用,其中有不少很有用的函式,在後面會陸續地介紹大家。
此外在初始化設定(也就是setup())部分的第30行:
server.on("/",handleRoot); // 定義處理客戶首頁連結請求的事件對應函式
在此我們用「server.on()」這個內建於” <ESP8266WebServer.h>”的函式,定義了當客戶端的瀏覽器如果連線並且要開啟伺服器的首頁(即請求的內容為「’/’」)時,對應的處理函式,也就是「handleRoot」這個自訂副程式,其實這個自訂副程式的實體內容(41~43行)很簡單,只有一行程式碼而已:
void handleRoot(){
server.send(200,"text/plain","ESP8266 AP模式--網路伺服器1"); //
}
其中使用了「server.send()」這個內建於” <ESP8266WebServer.h>”的函式,向發送請求的客戶端回應處理後的結果訊息;這些訊息包含了三個部分,第一個是HTTP的處理狀態代碼「200」,表示請求成功一切正常;再來是回傳的訊息內容格式「"text/plain"」,代表訊息內容是單純的文字,所以當客戶端的瀏覽器收到回應訊息後,會直接把它顯示出來,不做任何的解譯或處理;最後一個部分就是回應的訊息本身,在此就是「"ESP8266 AP模式--網路伺服器1"」這段文字。
在主體迴圈(loop())部分,我們將上一個範例程式抓取客戶端瀏覽器傳送訊息的部分拿掉,取而代之的是專用以監聽及處理客戶端連線請求的內建函式:
server.handleClient(); // 呼叫客戶端連線處理函式
這個函式一樣也是內建在” <ESP8266WebServer.h>”這個函式庫中,呼叫時不需要任何的引數,客戶端有任何連線請求出現時,會依前面setup()部分已呼叫過「server.on()」這個函式設定的請求內容及對應的自訂函式去回應。
HTTP狀態代碼
伺服器會使用HTTP狀態代碼回答所有請求,這個狀態代碼是一個3位數字,告訴客戶端請求是成功還是出了什麼問題。後面的表格包含一些最重要和最有用的狀態碼,以及它們所代表的意義。
以下便是此範例程式的全文:
// soft AP 範例四 : 以純文字(plain)的方式回應客戶端的首頁連線請求
#include <ESP8266WiFi.h> // 引入ESP8266專用的WiFi函式庫
#include <ESP8266WebServer.h> // 新增的ES8266網頁伺服器函式庫
String softSsid = "ESP_softAP01"; // 設定AP存取點的SSID名稱
const char* softPassword = "12345678"; // 設定AP存取點的密碼值
IPAddress local_IP(192,168,0,100); // 設定新的伺服器IP位址
IPAddress gateway(192,168,0,1); // 設定新的伺服器閘道位址
IPAddress subnet(255,255,255,0); // 設定新的伺服器網路遮罩位址
ESP8266WebServer server(80); // 設定伺服器使用的通信埠號碼為網頁專用的80
WiFiClient client;
void setup() {
//
Serial.begin(115200); // 初始化串列通訊埠
Serial.println();
Serial.print("Setting soft-AP with configuratin... ");
WiFi.softAPConfig(local_IP,gateway,subnet); // 設定新的本的IP位址
boolean result=WiFi.softAP(softSsid);
if(result==true)
{ // 初始化設定AP存取點成功
Serial.println("soft-AP ready!");
Serial.print("softAP = "); // 在Arduino IDE串列監控視窗中顯示目前
Serial.println(softSsid); // 顯示SSID名稱
Serial.print("softIP = "); // 在Arduino IDE串列監控視窗中顯示目前使用的
Serial.println(WiFi.softAPIP()); // 本地IP位址,在此為[ 192.168.0.100 ]
server.on("/",handleRoot); // 定義處理客戶首頁連結請求的事件對應函式
server.begin(); // 啟動伺服器功能
}
else
Serial.println("soft-AP failed");
}
void loop() {
server.handleClient(); // 呼叫客戶端連線處理函式
}
// 處理首頁’/’請求的自訂函式
void handleRoot(){
server.send(200,"text/plain","ESP8266 AP模式--網路伺服器1"); //
}
程式名稱:softAP3_webServer2.ino
◎ 執行結果:
圖六、9 手機啟動瀏覽器連接ESP8266伺服器成功畫面
在程式燒錄成功之後,當我們再次啟動手機瀏覽器連接上ESP8266的內建伺服器成功時,便可看到【圖六、9】的畫面,標記2的地方便是我要顯示的訊息;在ESP8266所構成的伺服器中,也可以處理中文的訊息,就跟一般的網頁一樣。不過一般的使用者在連上這個網頁時,可能看不到像【圖六、9】那麼好看的畫面,必須將手機的螢幕畫面拉大之後才能看到清楚的文字內容;這是因為我們的ESP8266網頁伺服器回傳的是最基本的文本(plain)格式的訊息,一般來說瀏覽器會以預設最小的字形來顯示,而且是放在螢幕的左上角,所以使用者必須費一番力氣才能看得到。
這種以基本的文本(plain)的格式回傳訊息的原因,大部分是因為使用者會以幕後處理的方式來解析與處理這些訊息,所以美不美觀並不是重點!如果想讓我們的網頁畫面好看一點,那就必須使用標準的網頁設計方式來設計我們的程式,也就使是用html語法,而這也就是下一章要介紹的內容。
沒有留言:
張貼留言