ESP8266開發之旅 網絡篇⑩ UDP服務

授人以魚不如授人以漁,目的不是爲了教會你具體項目開發,而是學會學習的能力。但願你們分享給你周邊須要的朋友或者同窗,說不定大神成長之路有博哥的奠定石。。。git

QQ技術互動交流羣:ESP8266&32 物聯網開發 羣號622368884,不喜勿噴web

1、你若是想學基於Arduino的ESP8266開發技術

1、基礎篇網絡

  1. ESP8266開發之旅 基礎篇① 走進ESP8266的世界
  2. ESP8266開發之旅 基礎篇② 如何安裝ESP8266的Arduino開發環境
  3. ESP8266開發之旅 基礎篇③ ESP8266與Arduino的開發說明
  4. ESP8266開發之旅 基礎篇④ ESP8266與EEPROM
  5. ESP8266開發之旅 基礎篇⑤ ESP8266 SPI通訊和I2C通訊
  6. ESP8266開發之旅 基礎篇⑥ Ticker——ESP8266定時庫

2、網絡篇socket

  1. ESP8266開發之旅 網絡篇① 認識一下Arduino Core For ESP8266
  2. ESP8266開發之旅 網絡篇② ESP8266 工做模式與ESP8266WiFi庫
  3. ESP8266開發之旅 網絡篇③ Soft-AP——ESP8266WiFiAP庫的使用
  4. ESP8266開發之旅 網絡篇④ Station——ESP8266WiFiSTA庫的使用
  5. ESP8266開發之旅 網絡篇⑤ Scan WiFi——ESP8266WiFiScan庫的使用
  6. ESP8266開發之旅 網絡篇⑥ ESP8266WiFiGeneric——基礎庫
  7. ESP8266開發之旅 網絡篇⑦ TCP Server & TCP Client
  8. ESP8266開發之旅 網絡篇⑧ SmartConfig——一鍵配網
  9. ESP8266開發之旅 網絡篇⑨ HttpClient——ESP8266HTTPClient庫的使用
  10. ESP8266開發之旅 網絡篇⑩ UDP服務
  11. ESP8266開發之旅 網絡篇⑪ WebServer——ESP8266WebServer庫的使用
  12. ESP8266開發之旅 網絡篇⑫ 域名服務——ESP8266mDNS庫
  13. ESP8266開發之旅 網絡篇⑬ SPIFFS——ESP8266 Flash文件系統
  14. ESP8266開發之旅 網絡篇⑭ web配網
  15. ESP8266開發之旅 網絡篇⑮ 真正的域名服務——DNSServer
  16. ESP8266開發之旅 網絡篇⑯ 無線更新——OTA固件更新

3、應用篇tcp

  1. ESP8266開發之旅 應用篇① 局域網應用 ——炫酷RGB彩燈
  2. ESP8266開發之旅 應用篇② OLED顯示天氣屏
  3. ESP8266開發之旅 應用篇③ 簡易版WiFi小車

4、高級篇函數

  1. ESP8266開發之旅 進階篇① 代碼優化 —— ESP8266內存管理
  2. ESP8266開發之旅 進階篇② 閒聊Arduino IDE For ESP8266配置
  3. ESP8266開發之旅 進階篇③ 閒聊 ESP8266 Flash
  4. ESP8266開發之旅 進階篇④ 常見問題 —— 解決困擾
  5. ESP8266開發之旅 進階篇⑤ 代碼規範 —— 像寫文章同樣優美
  6. ESP8266開發之旅 進階篇⑥ ESP-specific APIs說明

1. 前言

    前面的博文中,博主講述的內容基本上都是Tcp以及Http通訊的內容,那麼咱們固然得講解一下Tcp的另一個兄弟——UDP。oop

1.1 TCP與UDP優缺點

  1. TCP是面向鏈接,也就是發送數據以前是須要創建鏈接;UDP是面向無鏈接的,即發送數據以前不須要創建鏈接。
  2. TCP提供可靠的服務。也就是說,經過TCP鏈接傳送的數據,無差錯,不丟失,不重複,且按序到達;UDP盡最大努力作到可靠,即不保證絕對可靠。
  3. UDP具備較好的實時性,工做效率比TCP高,適用於對高速傳輸和實時性有較高的通訊或廣播通訊。
  4. 每一條TCP鏈接只能是點到點的;UDP支持一對一,一對多,多對一和多對多的交互通訊。
  5. TCP對系統資源要求較多,UDP對系統資源要求較少。

UDP 是 User Datagram Protocol 的簡稱,是一種無鏈接、不可靠的協議,每個數據報都是一個獨立的信息,它在網絡上以任何可能的路徑傳到目的地,但不保證是否真的傳到目的地、是否過程當中真的保證了數據的完整性!學習

UDP就好像無手機時代,你要去探望親戚,可是你不知道親戚有沒有在家(也就是說可能會丟包);測試

TCP就好像有手機時代,你要去探望親戚,你會打電話過去提早溝通好,你會確保親戚在家裏纔會買東西過去探望(數據不會丟包);優化

使用UDP服務,請在代碼前加入一下頭文件:

#include <WiFiUdp.h>

2. WiFiUDP庫

    老規矩,先上一個博主總結的百度腦圖:
image

整體上,根據功能能夠把方法分爲4大類:

  • 啓動UDP服務方法;
  • 處理髮送過來的UDP包;
  • 獲取UDP client的信息;
  • 發送UDP包;

2.1 啓動UDP服務方法

2.1.1 begin —— 開啓UDP服務

函數說明:

/**
 * 初始化TCP服務,開始監聽特定端口
 * @return  1 表示成功
 *          0 表示沒有有效的socket能夠用
 */
uint8_t begin(uint16_t port);

2.1.2 stop —— 中止UDP服務

函數說明:

/**
 * 斷開UDP鏈接
 */
void stop();

2.2 處理髮送過來的UDP包

2.2.1 parsePacket —— 解析UDP數據包

函數說明:

/**
 * 開始處理進來的UDP請求
 * @return  int 返回當前UDP包的大小,若是沒有就返回0
 */
int parsePacket();

注意點:

  • 此方法要在 available、read、peek以前調用(總結來講,就是讀取數據以前應該解析數據);

2.2.2 available —— 判斷UDP數據包可讀大小

函數說明:

/**
 * 返回當前udp包的可讀剩餘字節數據
 */
int available();

2.2.3 read —— 讀取數據並清除

函數說明:

/**
 * 讀取當前udp數據包的一個字節,並從緩衝區清除該字節
 * @return 單字節數據
 */
int read(); 

/**
 * 讀取當前udp數據包的len長度的數據,並從緩衝區清除該字節
 * @param buffer 存儲數據的內存空間
 * @param len 須要讀取的長度
 * @return 讀取成功字節數
 */
int read(unsigned char* buffer, size_t len);

注意點:

  • 此方法讀取完數據以後會把數據從緩衝區去掉;

2.2.4 peek —— 讀取數據

函數說明:

/**
 * 讀取當前udp數據包的一個字節
 * @return 單字節數據
 */
int peek();

注意點:

  • 此方法讀取完數據以後會不會把數據從緩衝區去掉;
  • 建議儘可能使用批量處理函數;

2.2.5 flush —— 清除緩衝區

函數說明:

/**
 * 清除緩衝區
 */
void flush();

2.3 獲取UDP 遠端的信息

2.3.1 remoteIP —— 遠端IP地址

函數說明:

/**
 * 獲取發送當前UDP包的主機IP地址
 * @return IPAddress ip地址
 */
IPAddress remoteIP();

2.3.2 remotePort —— 遠端端口

函數說明:

/**
 * 獲取發送當前UDP包的主機端口
 * @return uint16_t 端口
 */
uint16_t remotePort();

2.4 發送UDP包

2.4.1 beginPacket —— 配置ip和port

函數說明:

/**
 * 開始建立須要發送給遠端主機的udp包
 * @param ip 遠端主機ip地址
 * @param port 遠端主機端口號
 * @return 1 建立成功
 *         0 建立失敗
 */
int beginPacket(IPAddress ip, uint16_t port);
int beginPacket(const char *host, uint16_t port);

2.4.2 write —— 把數據寫入發送緩衝區

函數說明:

/**
 * 寫入一字節數據到建立好的udp包
 * @param uint8_t 單字節數據
 * @return 1 寫入成功
 *         0 寫入失敗
 */
size_t write(uint8_t);

/**
 * 寫入字節數據到建立好的udp包
 * @param buffer 字節數據緩衝區
 * @return size_t 返回寫入成功的字節數
 */ 
size_t write(const uint8_t *buffer);

/**
 * 寫入size字節數據到建立好的udp包
 * @param buffer 字節數據緩衝區
 * @param size 字節數據長度
 * @return size_t 返回寫入成功的字節數
 */ 
size_t write(const uint8_t *buffer, size_t size);

2.4.3 endPacket —— 發送數據

函數說明:

/**
 * 把udp數據包發送出去
 * @param uint8_t 單字節數據
 * @return 1 發送成功
 *         0 發送失敗
 */
int endPacket();

3. 實例

3.1 經過UDP收發數據

實例說明

  • ESP8266做爲UDP服務端,把電腦UDP客戶端發過來的數據打印到串口調試器,並回復應答信息;

源碼:

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

const char* ssid = "********";//wifi帳號
const char* password = "********";//wifi密碼

WiFiUDP Udp;
unsigned int localUdpPort = 4210;  // 本地監聽端口
char incomingPacket[255];  // 存儲Udp客戶端發過來的數據
char  replyPacket[] = "Hi there! Got the message :-)";  // 應答信息


void setup()
{
  Serial.begin(115200);
  Serial.println();

  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println(" connected");

  //啓動Udp監聽服務
  Udp.begin(localUdpPort);
  //打印本地ip地址,udp client端會使用到
  Serial.printf("Now listening at IP %s, UDP port %d\n", WiFi.localIP().toString().c_str(), localUdpPort);
}


void loop()
{
  //解析Udp數據包
  int packetSize = Udp.parsePacket();
  if (packetSize)
  {
    // 收到Udp數據包
    Serial.printf("Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
    // 讀取Udp數據包
    int len = Udp.read(incomingPacket, 255);
    if (len > 0)
    {
      incomingPacket[len] = 0;
    }
    //向串口調試器打印信息
    Serial.printf("UDP packet contents: %s\n", incomingPacket);

    //往udp 遠端發送應答信息
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(replyPacket);
    Udp.endPacket();
  }
}

注意點:

  • 爲了模擬UDP客戶端請求,請下載使用如下軟件 Packet Sender

測試結果:

  • ESP8266先開啓UDP服務,而後Packet Sender發送UDP數據:

image

image

3.2 經過UDP控制LED

實例說明

  • ESP8266做爲UDP服務端,把電腦UDP客戶端發過來的命令用來控制板載LED燈,其中 LED_ON 表示開燈,LED_OFF表示關燈,操做完畢後須要回覆信息;

源碼:

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

const char *ssid = "********";     //wifi名稱
const char *password = "********"; //wifi密碼

WiFiUDP Udp;
unsigned int localUdpPort = 4210; // 本地端口號
char incomingPacket[255];         // 接收緩衝區

void setup()
{
  //如下爲基本功能初始化,初始化串口和網絡和LED
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(115200);
  Serial.println();
  Serial.printf("Connecting to %s ", ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println(" connected");

  //如下開啓UDP監聽並打印輸出信息
  Udp.begin(localUdpPort);
  Serial.printf("Now listening at IP %s, UDP port %d\n", WiFi.localIP().toString().c_str(), localUdpPort);
}

void loop()
{
  int packetSize = Udp.parsePacket(); //獲取當前隊首數據包長度
  if (packetSize)  // 有數據可用
  {
    Serial.printf("Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
    int len = Udp.read(incomingPacket, 255); // 讀取數據到incomingPacket
    if (len > 0)                             // 若是正確讀取
    {
      incomingPacket[len] = 0; //末尾補0結束字符串
      Serial.printf("UDP packet contents: %s\n", incomingPacket);

      if (strcmp(incomingPacket, "LED_OFF") == 0) // 命令LED_OFF
      {
        digitalWrite(LED_BUILTIN, HIGH); // 熄滅LED
        sendCallBack("LED has been turn off");
      }
      else if (strcmp(incomingPacket, "LED_ON") == 0) // 若是收到LED_ON
      {
        digitalWrite(LED_BUILTIN, LOW); // 點亮LED
        sendCallBack("LED has been turn on");
      }
      else // 若是非指定消息
      {
        sendCallBack("Command Error!");
      }
    }
  }
}

/**
 * 發送響應信息
 */
void sendCallBack(const char *buffer){
   Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
   Udp.write(buffer); //回覆內容
   Udp.endPacket(); 
}

測試結果:

  • ESP8266先開啓UDP服務,而後Packet Sender發送UDP命令:
    image

image

4. 總結

使用Arduino for esp8266能夠很是簡單實現UDP通信過程。最重要須要記住的一點,那就是UDP面向無鏈接,發送出去的數據不會理會是否被收到。

相關文章
相關標籤/搜索