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:
- Set up the Server: Upload Example 1 (UDP Server) to your first ESP32 and note its IP address from the Serial Monitor
- Configure the Client: In Example 2 (UDP Client), update the
SERVER_IPconstant with your server’s IP address - Deploy the Client: Upload Example 2 to a second ESP32 or compatible device
- 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
- 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 WiFi Library
- ESP32 WiFiClient Library
- ESP32 HTTPClient Library
- ESP32 WiFiClientSecure Library
- ESP32 WebServer Library
- ESP32 AsyncUDP Librarry
- Connection Management
- Data Transimission
- Broadcast Multicast
- Network Information
- Which ESP32 Boards are Recommended for Learners
- How to Copy Codes from AvantMaker.com
- What is SPIFFS and how to upload files to it?
- What is LIttleFS and how to upload files to it?
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!