ESP32 AsyncUDP Library – peek()

Home / References / ESP32 Library / AsyncUDP Library

Description

The peek() method is a fundamental function of the AsyncUDPPacket class that provides non-destructive access to the next byte in the received UDP packet data. This method allows developers to examine the next byte in the packet buffer without actually consuming or removing it from the data stream. Unlike the read() method which advances the internal buffer position, peek() leaves the buffer position unchanged, enabling repeated examination of the same byte or look-ahead operations. This functionality is essential for protocol parsing, data validation, and decision-making processes where you need to examine data before committing to processing it.

Syntax and Usage

The peek() method can be used in the following way:

  • Basic Usage: int nextByte = packet.peek(); – Retrieves the next byte without consuming it from the buffer
// Example of basic usage
void onPacketReceived(AsyncUDPPacket packet) {
    if (packet.available() > 0) {
        int nextByte = packet.peek();
        // Examine the byte without consuming it
        // Buffer position remains unchanged
    }
}

Argument(s)

This method does not require any arguments.

Return Value

The peek() method returns an int value that represents the next available byte in the packet buffer. The return value can be:

  • 0-255: The actual byte value at the current buffer position
  • -1: Indicates that no more data is available in the buffer (equivalent to end-of-data)

The key characteristic of peek() is that calling it multiple times consecutively will return the same byte value, as it does not advance the internal buffer index. This behavior differs from read(), which would return different bytes on consecutive calls.

Example Codes

How to Use Both Examples Together

To fully test the peek() method functionality and understand its capabilities for protocol parsing and data validation, follow these steps:

  1. Set up the Server: Upload Example 1 (UDP Server) to your first ESP32 and note its IP address from the Serial Monitor
  2. Configure the Client: In Example 2 (UDP Client), update the SERVER_IP constant with your server’s IP address
  3. Deploy the Client: Upload Example 2 to a second ESP32 or compatible device
  4. Observe the Testing: The client will automatically send various types of structured data every 5 seconds:
    • Headered messages with type and length prefixes
    • Protocol messages with start/end markers and payload sizes
    • Sensor data packets with type identifiers
    • Command packets with structured parameters
    • Malformed packets for error handling demonstration
  5. Monitor Results: Watch both Serial Monitors to see how the peek() method enables:
    • Non-destructive examination of packet headers
    • Protocol type identification before processing
    • Data validation without consuming bytes
    • Look-ahead operations for decision making
    • Error detection and graceful handling

This comprehensive testing setup demonstrates the power and versatility of the peek() method in handling complex UDP communication scenarios. The method’s ability to examine data without consuming it makes it invaluable for building robust, protocol-aware ESP32 applications that need to parse and validate incoming UDP packets before processing them.

Example 1: UDP Server (Receiver) – Comprehensive peek() Method Demonstration

This example demonstrates various uses of the peek() method for protocol parsing, data validation, and look-ahead operations. The receiver showcases how peek() can be used for examining data without consuming it.

/*
* Author: Avant Maker
* Date: June 23, 2025
* Version: 1.0
* License: MIT
* 
* Description: 
* Comprehensive demonstration of the AsyncUDP peek() method for ESP32.
* This receiver code shows different ways to use the peek() method
* to examine data without consuming it, useful for protocol parsing,
* data validation, and look-ahead operations.
* This is the RECEIVER/SERVER code.
*
* Setup Instructions:
* 1. Upload this code to your ESP32 (Server)
* 2. Note the IP address shown in Serial Monitor
* 3. Update the sender code with this IP address
* 4. Upload and run the sender code on another ESP32
* 5. Watch the Serial Monitor to see peek() method demonstrations
*
* Code Source:
* This example code is sourced from the Comprehensive Guide
* to the ESP32 Arduino Core Library, accessible on AvantMaker.com.
* For additional code examples and in-depth documentation related to
* the ESP32 Arduino Core Library, please visit:
*
* https://avantmaker.com/home/all-about-esp32-arduino-core-library/
*
* AvantMaker.com - Your Premier Hub for DIY, AI, IoT, and STEM Innovation
*/

#include <WiFi.h>
#include <AsyncUDP.h>

const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";

AsyncUDP udp;

void setup() {
    Serial.begin(115200);
    delay(1000);
    
    Serial.println("=== AsyncUDP peek() Method Demo - Receiver ===");
    
    // Connect to WiFi
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("\nWiFi connected!");
    Serial.print("Server IP: ");
    Serial.println(WiFi.localIP());
    
    // Start UDP listener on port 1234
    if (udp.listen(1234)) {
        Serial.println("UDP Server listening on port 1234");
        Serial.println("Waiting for packets to demonstrate peek() method...\n");
        
        udp.onPacket([](AsyncUDPPacket packet) {
            Serial.println("========================");
            Serial.println("--- Packet Received ---");
            Serial.print("Total Length: ");
            Serial.print(packet.length());
            Serial.println(" bytes");
            
            // Demonstration 1: Basic peek() vs read() comparison
            demonstratePeekVsRead(packet);
            
            // Reset packet position for next demo
            // Note: peek() doesn't consume bytes, but read() does
            // So we need to work with available data carefully
            
            // Demonstration 2: Protocol parsing using peek()
            demonstrateProtocolParsing(packet);
            
            // Demonstration 3: Data validation using peek()
            demonstrateDataValidation(packet);
            
            // Demonstration 4: Look-ahead operations
            demonstrateLookAhead(packet);
            
            Serial.println("========================\n");
        });
    } else {
        Serial.println("Failed to start UDP server!");
    }
}

void loop() {
    delay(1000);
}

void demonstratePeekVsRead(AsyncUDPPacket& packet) {
    Serial.println("\n1. PEEK vs READ Comparison:");
    Serial.println("peek() looks at data without consuming it");
    Serial.println("read() consumes the data from buffer");
    
    if (packet.available() > 0) {
        // Use peek() to look at first byte without consuming it
        int firstByte = packet.peek();
        Serial.print("peek() - First byte: ");
        Serial.print(firstByte);
        Serial.print(" (0x");
        Serial.print(firstByte, HEX);
        Serial.print(") '");
        Serial.print((char)firstByte);
        Serial.print("' - Available after peek: ");
        Serial.println(packet.available());
        
        // Peek again - should return same byte
        int peekAgain = packet.peek();
        Serial.print("peek() again - Same byte: ");
        Serial.print(peekAgain);
        Serial.print(" - Available: ");
        Serial.println(packet.available());
        
        // Now use read() to consume the byte
        int readByte = packet.read();
        Serial.print("read() - Consumed byte: ");
        Serial.print(readByte);
        Serial.print(" - Available after read: ");
        Serial.println(packet.available());
    }
}

void demonstrateProtocolParsing(AsyncUDPPacket& packet) {
    Serial.println("\n2. PROTOCOL PARSING with peek():");
    Serial.println("Using peek() to identify packet type before processing");
    
    if (packet.available() == 0) return;
    
    // Look at the first byte to determine packet type
    int packetType = packet.peek();
    Serial.print("Packet type identifier: ");
    Serial.print(packetType);
    Serial.print(" (0x");
    Serial.print(packetType, HEX);
    Serial.print(") '");
    Serial.print((char)packetType);
    Serial.println("'");
    
    // Process based on packet type
    switch ((char)packetType) {
        case 'T':
            parseHeaderedMessage(packet);
            break;
        case 0xAA:  // Protocol start marker
            parseProtocolMessage(packet);
            break;
        case 'S':
            parseSensorData(packet);
            break;
        case 'C':
            parseCommandPacket(packet);
            break;
        case 'X':
            parseMalformedPacket(packet);
            break;
        default:
            Serial.println("Unknown packet type - skipping");
            break;
    }
}

void parseHeaderedMessage(AsyncUDPPacket& packet) {
    Serial.println("→ Parsing HEADERED MESSAGE:");
    
    if (packet.available() < 2) {
        Serial.println("  Error: Insufficient data for header");
        return;
    }
    
    packet.read();  // Consume type byte
    int length = packet.peek();  // Peek at length
    Serial.print("  Declared length: ");
    Serial.println(length);
    
    packet.read();  // Consume length byte
    
    if (packet.available() < length) {
        Serial.println("  Error: Insufficient data for declared length");
        return;
    }
    
    Serial.print("  Message: \"");
    for (int i = 0; i < length && packet.available() > 0; i++) {
        Serial.print((char)packet.read());
    }
    Serial.println("\"");
}

void parseProtocolMessage(AsyncUDPPacket& packet) {
    Serial.println("→ Parsing PROTOCOL MESSAGE:");
    
    if (packet.available() < 4) {
        Serial.println("  Error: Insufficient data for protocol header");
        return;
    }
    
    // Validate protocol structure using peek()
    if (packet.peek() != 0xAA) {
        Serial.println("  Error: Invalid start marker");
        return;
    }
    
    packet.read();  // Consume start marker
    int command = packet.read();
    int payloadSize = packet.peek();  // Peek at payload size
    
    Serial.print("  Command: 0x");
    Serial.println(command, HEX);
    Serial.print("  Payload size: ");
    Serial.println(payloadSize);
    
    packet.read();  // Consume payload size
    
    if (packet.available() < payloadSize + 1) {  // +1 for end marker
        Serial.println("  Error: Insufficient data for payload and end marker");
        return;
    }
    
    Serial.print("  Payload: \"");
    for (int i = 0; i < payloadSize; i++) {
        Serial.print((char)packet.read());
    }
    Serial.println("\"");
    
    int endMarker = packet.read();
    if (endMarker == 0x55) {
        Serial.println("  Protocol message parsed successfully");
    } else {
        Serial.print("  Warning: Invalid end marker: 0x");
        Serial.println(endMarker, HEX);
    }
}

void parseSensorData(AsyncUDPPacket& packet) {
    Serial.println("→ Parsing SENSOR DATA:");
    
    if (packet.available() < 4) {
        Serial.println("  Error: Insufficient sensor data");
        return;
    }
    
    packet.read();  // Consume sensor ID
    char dataType = (char)packet.read();
    
    Serial.print("  Data type: ");
    Serial.println(dataType);
    
    if (dataType == 'T') {  // Temperature
        int wholePart = packet.read();
        int decimalPart = packet.read();
        Serial.print("  Temperature: ");
        Serial.print(wholePart);
        Serial.print(".");
        Serial.print(decimalPart);
        Serial.println("°C");
    }
}

void parseCommandPacket(AsyncUDPPacket& packet) {
    Serial.println("→ Parsing COMMAND PACKET:");
    
    if (packet.available() < 5) {
        Serial.println("  Error: Insufficient command data");
        return;
    }
    
    packet.read();  // Consume prefix
    char command = (char)packet.read();
    
    Serial.print("  Command: ");
    Serial.println(command);
    
    if (command == 'L') {  // LED command
        int red = packet.read();
        int green = packet.read();
        int blue = packet.read();
        Serial.print("  RGB Values: (");
        Serial.print(red);
        Serial.print(", ");
        Serial.print(green);
        Serial.print(", ");
        Serial.print(blue);
        Serial.println(")");
    }
}

void parseMalformedPacket(AsyncUDPPacket& packet) {
    Serial.println("→ Parsing MALFORMED PACKET (Error Handling Demo):");
    
    packet.read();  // Consume type
    int claimedLength = packet.read();
    int actualRemaining = packet.available();
    
    Serial.print("  Claimed data length: ");
    Serial.println(claimedLength);
    Serial.print("  Actual remaining bytes: ");
    Serial.println(actualRemaining);
    
    if (actualRemaining < claimedLength) {
        Serial.println("  Error: Malformed packet detected - length mismatch!");
        Serial.println("  Safely handling by reading only available data...");
        
        Serial.print("  Available data: \"");
        while (packet.available() > 0) {
            Serial.print((char)packet.read());
        }
        Serial.println("\"");
    }
}

void demonstrateDataValidation(AsyncUDPPacket& packet) {
    Serial.println("\n3. DATA VALIDATION with peek():");
    Serial.println("Using peek() to validate data before processing");
    
    // This function would typically be called on a fresh packet
    // but for demo purposes, we'll work with what's available
    if (packet.available() == 0) {
        Serial.println("No data available for validation demo");
        return;
    }
    
    Serial.print("Bytes remaining for validation: ");
    Serial.println(packet.available());
}

void demonstrateLookAhead(AsyncUDPPacket& packet) {
    Serial.println("\n4. LOOK-AHEAD OPERATIONS with peek():");
    Serial.println("Using peek() for decision making without consuming data");
    
    if (packet.available() == 0) {
        Serial.println("No data available for look-ahead demo");
        return;
    }
    
    Serial.print("Final bytes remaining: ");
    Serial.println(packet.available());
    
    // Demonstrate looking ahead at remaining bytes
    Serial.print("Remaining bytes: ");
    int position = 0;
    while (packet.available() > 0) {
        int byte = packet.read();  // Have to consume for this demo
        Serial.print(byte);
        Serial.print(" ");
    }
    Serial.println();
}

Example 2: UDP Client (Sender) – Testing Companion Code

This companion example acts as a UDP client that sends various types of structured data packets to test the peek() method functionality on the receiving ESP32. The sender creates different packet formats with headers and structured data to demonstrate protocol parsing capabilities.

/*
* Author: Avant Maker
* Date: June 23, 2025
* Version: 1.0
* License: MIT
* 
* Description: 
* Simple sender code to test the AsyncUDP peek() method demonstration.
* This client sends various types of data packets with headers and
* structured data to help demonstrate how the peek() method works
* on the receiver side for protocol parsing and data validation.
* This is the SENDER/CLIENT code.
*
* Setup Instructions:
* 1. First run the receiver code and note its IP address
* 2. Update SERVER_IP below with the receiver's IP address
* 3. Upload this code to another ESP32 (Client)
* 4. Watch both Serial Monitors to see the peek() method in action
*
* Code Source:
* This example code is sourced from the Comprehensive Guide
* to the ESP32 Arduino Core Library, accessible on AvantMaker.com.
* For additional code examples and in-depth documentation related to
* the ESP32 Arduino Core Library, please visit:
*
* https://avantmaker.com/home/all-about-esp32-arduino-core-library/
*
* AvantMaker.com - Your Premier Hub for DIY, AI, IoT, and STEM Innovation
*/

#include <WiFi.h>
#include <AsyncUDP.h>

const char* ssid = "your_SSID";          // Replace with your Wi-Fi SSID
const char* password = "your_PASSWORD";  // Replace with your Wi-Fi password

// Update this with your receiver ESP32's IP address
const char* SERVER_IP = "192.168.0.123";  // CHANGE THIS!
const int SERVER_PORT = 1234;

AsyncUDP udp;
IPAddress serverIP;
int packetCounter = 0;

void setup() {
    Serial.begin(115200);
    delay(1000);
    
    Serial.println("=== AsyncUDP peek() Method Demo - Sender ===");
    
    // Convert IP string to IPAddress
    serverIP.fromString(SERVER_IP);
    Serial.print("Target server: ");
    Serial.println(serverIP);
    
    // Connect to WiFi
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("\nWiFi connected!");
    Serial.print("Client IP: ");
    Serial.println(WiFi.localIP());
    Serial.println("Sending test packets every 5 seconds...\n");
}

void loop() {
    packetCounter++;
    Serial.print("Sending packet #");
    Serial.println(packetCounter);
    
    // Send different types of structured data to test peek() method
    switch (packetCounter % 5) {
        case 1:
            sendHeaderedMessage();
            break;
        case 2:
            sendProtocolMessage();
            break;
        case 3:
            sendSensorData();
            break;
        case 4:
            sendCommandPacket();
            break;
        case 0:
            sendMalformedPacket();
            break;
    }
    
    delay(5000);  // Wait 5 seconds between packets
}

void sendHeaderedMessage() {
    // Format: [TYPE][LENGTH][DATA]
    uint8_t packet[] = {'T', 12, 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'};
    
    Serial.print("Sending headered message: Type=");
    Serial.print((char)packet[0]);
    Serial.print(", Length=");
    Serial.print(packet[1]);
    Serial.print(", Data=\"");
    for (int i = 2; i < sizeof(packet); i++) {
        Serial.print((char)packet[i]);
    }
    Serial.println("\"");
    
    size_t sent = udp.writeTo(packet, sizeof(packet), serverIP, SERVER_PORT);
    Serial.print("Bytes sent: ");
    Serial.println(sent);
    Serial.println();
}

void sendProtocolMessage() {
    // Format: [START_MARKER][COMMAND][PAYLOAD_SIZE][PAYLOAD][END_MARKER]
    uint8_t packet[] = {0xAA, 0x01, 0x06, 'S', 'T', 'A', 'T', 'U', 'S', 0x55};
    
    Serial.print("Sending protocol message: Start=0x");
    Serial.print(packet[0], HEX);
    Serial.print(", Cmd=0x");
    Serial.print(packet[1], HEX);
    Serial.print(", Size=");
    Serial.print(packet[2]);
    Serial.print(", Data=\"");
    for (int i = 3; i < 9; i++) {
        Serial.print((char)packet[i]);
    }
    Serial.print("\", End=0x");
    Serial.print(packet[9], HEX);
    Serial.println();
    
    size_t sent = udp.writeTo(packet, sizeof(packet), serverIP, SERVER_PORT);
    Serial.print("Bytes sent: ");
    Serial.println(sent);
    Serial.println();
}

void sendSensorData() {
    // Format: [SENSOR_ID][DATA_TYPE][VALUE_BYTES]
    uint8_t packet[] = {'S', 'T', 23, 45};  // Sensor ID='S', Type='T' (Temperature), Value=23.45°C (as bytes)
    
    Serial.print("Sending sensor data: ID=");
    Serial.print((char)packet[0]);
    Serial.print(", Type=");
    Serial.print((char)packet[1]);
    Serial.print(", Value=");
    Serial.print(packet[2]);
    Serial.print(".");
    Serial.print(packet[3]);
    Serial.println("°C");
    
    size_t sent = udp.writeTo(packet, sizeof(packet), serverIP, SERVER_PORT);
    Serial.print("Bytes sent: ");
    Serial.println(sent);
    Serial.println();
}

void sendCommandPacket() {
    // Format: [CMD_PREFIX][COMMAND][PARAMS]
    uint8_t packet[] = {'C', 'L', 255, 128, 64};  // Command='L' (LED), R=255, G=128, B=64
    
    Serial.print("Sending command: Prefix=");
    Serial.print((char)packet[0]);
    Serial.print(", Command=");
    Serial.print((char)packet[1]);
    Serial.print(", RGB=(");
    Serial.print(packet[2]);
    Serial.print(",");
    Serial.print(packet[3]);
    Serial.print(",");
    Serial.print(packet[4]);
    Serial.println(")");
    
    size_t sent = udp.writeTo(packet, sizeof(packet), serverIP, SERVER_PORT);
    Serial.print("Bytes sent: ");
    Serial.println(sent);
    Serial.println();
}

void sendMalformedPacket() {
    // Intentionally malformed packet to test error handling
    uint8_t packet[] = {'X', 99, 'B', 'A', 'D'};  // Claims length=99 but only has 3 data bytes
    
    Serial.println("Sending malformed packet (for error handling demo)");
    Serial.print("Claims length=");
    Serial.print(packet[1]);
    Serial.println(" but actual data is shorter");
    
    size_t sent = udp.writeTo(packet, sizeof(packet), serverIP, SERVER_PORT);
    Serial.print("Bytes sent: ");
    Serial.println(sent);
    Serial.println();
}

ESP32 Library Index

ESP32 Arduino Core Library


FAQ

Ready to experiment and explore more about ESP32? Visit our website’s All About ESP32 Resources Hub, packed with tutorials, guides, and tools to inspire your maker journey. Experiment, explore, and elevate your skills with everything you need to master this powerful microcontroller platform!

error: Content is protected !!