WiFiUDP の解説と実装リファレンス

記事内には広告が含まれています。

WiFiUDP の解説と実装リファレンス

【概要】

WiFiUDP クラスは、Arduino環境(主にESP8266およびESP32)において、Wi-Fiネットワーク経由でUDP(User Datagram Protocol)プロトコルを用いた通信を行うためのライブラリです。

UDPはTCPと比較してコネクションの確立(3ウェイ・ハンドシェイク)を行わないため、低遅延かつオーバーヘッドの少ない通信が可能です。このクラスは、UDPソケットの作成、パケットの受信、送信、およびリモートホスト情報の取得を抽象化し、標準的なArduinoのプログラミングモデルで操作できるように提供されます。

【仕様】

主要なメソッドと関数

| 関数名 | 引数 | 戻り値 | 説明 |
| WiFiUDP(uint16_t port) | port (uint16_t) | なし | 指定したポート番号でUDPソケットを初期化するコンストラクタ。 |
| begin() | なし | なし | UDPソケットをアクティブな状態にする。 |
| parsePacket() | なし | bool | 受信バッファにパケットが存在するか確認し、存在する場合は内部ポインタを更新する。 |
| packetAvailable() | なし | bool | 受信可能なパケットがあるかを確認する(parsePacketと類似)。 |
| dump() | なし | なし | 受信したパケットの全内容をシリアル出力に表示する。 |
| write() | uint8_t* (payload), size_t (length) | size_t | パケットを送信し、実際に送信されたバイト数を返す。 |
| remote_IP() | なし | IPAddress | 送信元(パケット送信元)のIPアドレスを取得する。 |
| remote_port() | なし | uint16_t | 送信元ポート番号を取得する。 |
| packetSize() | なし | size_t | 受信パケットのサイズを取得する。 |

データ型と初期状態

  • ポート番号: 0〜65535(16ビット符号なし整数)。
  • バッファ処理: 内部的に受信バッファを保持するが、巨大なパケットの処理には注意が必要。
  • 初期状態: オブジェクト生成直後は初期化されておらず、begin()の呼び出しが必要。

【技術的特徴】

UDP vs TCP (WiFiClient)

  • 信頼性: WiFiUDPは「ベストエフォート」型の配送を行うため、パケットの到着保証や順序保証、再送制御は行われません。これに対しWiFiClient(TCP)は信頼性を保証します。
  • オーバーヘッド: UDPはヘッダサイズが小さく、通信の確立を必要としないため、リアルタイム性が求められる用途に適しています。
  • 非ブロッキング挙動: 一般的に、UDPの送信は送信バッファに書き込めば完了とみなされるため、TCPのような「送信完了待ち」のブロッキングが発生しにくい性質があります。

ハードウェアレベルの挙動

  • ソケット管理: ESP32/ESP8266のWi-Fiスタック(LwIPなど)と連携し、ハードウェアのネットワークインターフェースを介してパケットを処理します。
  • マルチキャスト/ブロードキャスト: WiFiUDPを通じて、ネットワーク内の特定グループ(マルチキャスト)や全ホスト(ブロードキャスト)へのパケット送信をサポートします。

【注意点】

  1. パケット損失: 通信環境が不安定な場合、パケットは消失する可能性があります。重要なデータの送信にはアプリケーション層でのシーケンス番号やACKの設計が必要です。
  2. MTU制限: 通常のEthernet/Wi-Fi環境ではMTU(Maximum Transmission Unit)は1500バイト程度です。これを超えるサイズのパケットを一度に送信しようとすると、断片化(フラグメンテーション)が発生するか、破棄される可能性があります。
  3. リソース制約: 受信バッファはメモリを消費します。極端に大きなパケットの受信は、スタックオーバーフローやメモリ不足の原因となる可能性があります。
  4. 割り込みの影響: parsePacket()を実行するタイミングによっては、受信バッファが上書きされる可能性があります。高頻度でデータを受信する際は、受信間隔と処理速度のバランスを考慮する必要があります。
  5. 非同期処理: 受信パケットの処理が重い場合、次のパケットの処理を遅延させる可能性があります。重い処理は別タスク(ESP32のFreeRTOS等)にオフロードすることを推奨します。

【サンプルコード】

以下は、特定ポートで待機し、受信したデータを受信元とともに表示するUDPサーバーの基本実装です。

#include <WiFi.h>
#include <WiFiUDP.h>

const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

WiFiUDP udp;
unsigned int localPort = 4210; // 受信ポート

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("Connected to WiFi");
  udp.begin(localPort);
  Serial.print("Listening on port: ");
  Serial.println(localPort);
}

void loop() {
  int packetSize = udp.parsePacket();

  if (packetSize) {
    Serial.print("Received packet from: ");
    Serial.print(udp.remoteIP());
    Serial.print(" : ");
    Serial.print(udp.remotePort());

    while (udp.available()) {
      char c = udp.read();
      Serial.print(c);
    }
    Serial.println();
  }
}

【活用例】

  • IoTセンサー監視: 多数のデバイスから定期的にセンサー値を送信する「ハートビート」信号の受信。
  • 低遅延ビデオ/音声ストリーミング: 信頼性よりもリアルタイム性が重視されるメディアデータの転送。
  • DNSクエリ/簡易コマンド制御: 簡潔なコマンド(例:"LIGHT_ON")を特定のポートに投げて機器を操作するインターフェース。
  • マルチキャスト・ディスカバリー: ネットワーク内の特定のデバイスを探索するためのプロトコル実装。

コメント

タイトルとURLをコピーしました