NetBurner 3.5.6
PDF Version
UDP Protocol

UDP Protocol

The NetBurner API provides two methods to implement UDP: a C++ class interface and traditional socket functions. Both methods offer equivalent performance; choose based on your coding preference.

UDP Implementation Comparison

Class Interface Socket Interface
┌──────────────┐ ┌──────────────┐
UDPPacket │ │ recvfrom() │
│ .Send() │ vs │ sendto() │
│ .Validate() │ │ select() │
└──────────────┘ └──────────────┘
Object-oriented Function-based
UDP Packet Class - Complete UDP packet management.
Definition udp.h:602
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, unsigned long timeout)
Wait for events to occur on one or more I/O resources associated with a set of file descriptors (fds)...
int recvfrom(int sock, puint8_t buffer, int len, IPADDR *pAddr, uint16_t *pLocal_port, uint16_t *pRemote_port)
Receive UDP packet from socket with sender information.
Definition udp.h:5960
int sendto(int sock, puint8_t what_to_send, int len_to_send, const IPADDR &to_addr, uint16_t remote_port)
Send UDP packet through socket to specified destination.
Definition udp.h:5876

UDP Class Interface

The UDPPacket class provides an object-oriented approach to UDP communication.

Receiving UDP Packets (Class Method)

Setup Process**:

  1. Create an OS_FIFO to hold incoming packets
  2. Register the FIFO with RegisterUDPFifo() for specific port(s)
  3. Construct UDPPacket object to receive packets (blocking)
  4. Validate packet with Validate() member function
  5. Extract data with GetDataBuffer() member function

    Multi-Port Listening**:

  • Use separate OS_FIFO for each port, OR
  • Use single OS_FIFO for multiple ports by calling RegisterUDPFifo() multiple times

Sending UDP Packets (Class Method)

Transmission Process**:

  1. Declare UDPPacket instance
  2. Set source and destination ports
  3. Add data using member functions
  4. Call Send() to transmit packet

UDP Class Example

This example demonstrates bidirectional UDP communication using the UDPPacket class.

/*
UDP Send/Receive Example using UDPPacket Class
Features:
- Receives UDP packets and displays on serial port
- Sends user-typed messages as UDP packets
- Uses OS_FIFO for packet buffering
- Demonstrates task-based architecture
Testing:
- Use NetBurner UDP Terminal on Windows
- Configure matching IP addresses and ports
- Messages sent from terminal appear in MTTTY
- Messages typed in MTTTY sent via UDP
*/
#include <init.h>
#include <stdlib.h>
#include <system.h>
#include <udp.h>
#include <utils.h>
const char *AppName = "UDP Send/Receive Example";
// Allocate stack space for the listen task
uint32_t UdpReceiveTaskStack[USER_TASK_STK_SIZE];
/*
UDP Receive Task
Waits for incoming packets on specified port
*/
void UdpReceiveTask(void *pd)
{
static OS_FIFO fifo; // FIFO for incoming packets
int listenPort = (int)pd;
printf("Listening on UDP port: %d\r\n", listenPort);
// Register FIFO to receive packets on this port
RegisterUDPFifo(listenPort, &fifo);
while (1)
{
// Construct UDP packet object (blocks until packet received)
// Second parameter is timeout (0 = wait forever)
UDPPacket upkt(&fifo, 0 * TICKS_PER_SECOND);
// Check if valid packet received
if (upkt.Validate())
{
uint16_t len = upkt.GetDataSize();
printf("Received UDP packet with %d bytes from: %I\r\n",
(int)len, upkt.GetSourceAddress());
ShowData(upkt.GetDataBuffer(), len); // Hex dump
printf("\r\n");
}
}
}
/*
User Main
*/
void UserMain(void *pd)
{
int portNumber;
IPADDR destIpAddress;
char buffer[80];
init();
printf("Application: %s\r\nNNDK Revision: %s\r\n",
AppName, GetReleaseTag());
printf("Enter the UDP port number (send & receive): ");
gets(buffer);
portNumber = atoi(buffer);
printf("\r\nEnter the destination IP Address: ");
gets(buffer);
destIpAddress = AsciiToIp(buffer);
printf("Listening/Sending on UDP Port %d, Sending to: %I\r\n",
portNumber, destIpAddress);
// Create UDP receive task
OSTaskCreatewName(UdpReceiveTask,
(void *)portNumber,
&UdpReceiveTaskStack[USER_TASK_STK_SIZE],
UdpReceiveTaskStack,
MAIN_PRIO - 1, // Higher priority than UserMain
"UDP Receive");
// Main loop: send user input as UDP packets
printf("Enter data and hit return to send.\r\n");
while (1)
{
gets(buffer);
UDPPacket pkt;
pkt.SetSourcePort(portNumber);
pkt.SetDestinationPort(portNumber);
pkt.AddData(buffer);
pkt.AddDataByte(0);
pkt.Send(destIpAddress);
printf("\r\n");
printf("Sent \"%s\" to %I:%d\r\n", buffer, destIpAddress, portNumber);
}
}
Used to hold and manipulate IPv4 and IPv6 addresses in dual stack mode.
Definition ipv6_addr.h:41
void Send(const IPADDR &to, uint8_t ttl=0)
Send and free buffer (recommended - most efficient)
Definition udp.h:3391
void SetDestinationPort(uint16_t port)
Set destination port (standard services: 53=DNS, 80=HTTP, 123=NTP, 161=SNMP)
void SetSourcePort(uint16_t port)
Set source port (0=auto-assign ephemeral port, 1024-65535=specific port)
void AddData(puint8_t pData, uint16_t len)
Add binary data (auto-updates size - no SetDataSize() needed)
void AddDataByte(uint8_t b)
Add 8-bit value.
void ShowData(const uint8_t *fromptr, uint16_t len)
Dump a block of data to stdio and show in ASCII and hex.
#define TICKS_PER_SECOND
System clock ticks per second.
Definition constants.h:49
#define MAIN_PRIO
Recommend UserMain priority.
Definition constants.h:130
bool RegisterUDPFifo(uint16_t listenPort, OS_FIFO *pFifo)
Register FIFO to receive UDP packets on specified port.
const char * GetReleaseTag()
Returns the NNDK release tag information.
void init()
System initialization. Ideally called at the beginning of all applications, since the easiest Recover...
bool WaitForActiveNetwork(uint32_t ticks_to_wait=120 *TICKS_PER_SECOND, int interface=-1)
Wait for an active network connection on at least one interface.

UDP Class Architecture

Task Architecture:
┌────────────────────────────────────────────────┐
│ UserMain Task │
│ ┌───────────────────────────────────────────┐ │
│ │ 1. Get port and destination IP │ │
│ │ 2. Create UdpReceiveTask │ │
│ │ 3. Loop: │ │
│ │ ├─> Read user input │ │
│ │ ├─> Create UDPPacket │ │
│ │ ├─> Set ports │ │
│ │ ├─> Add data │ │
│ │ └─> Send() │ │
│ └───────────────────────────────────────────┘ │
└────────────────────────────────────────────────┘
┌────────────────────────────────────────────────┐
│ UdpReceiveTask (Higher Priority) │
│ ┌───────────────────────────────────────────┐ │
│ │ 1. Create OS_FIFO │ │
│ │ 2. RegisterUDPFifo(port, &fifo) │ │
│ │ 3. Loop: │ │
│ │ ├─> UDPPacket upkt(&fifo, timeout) │ │
│ │ │ [BLOCKS until packet received] │ │
│ │ ├─> Validate() │ │
│ │ ├─> GetDataBuffer() │ │
│ │ └─> Display data │ │
│ └───────────────────────────────────────────┘ │
└────────────────────────────────────────────────┘

Key Class Methods

Sending**:

pkt.SetSourcePort(localPort);
pkt.SetDestinationPort(remotePort);
pkt.AddData(dataBuffer);
pkt.Send(destinationIP);

Receiving**:

OS_FIFO fifo;
RegisterUDPFifo(port, &fifo);
UDPPacket upkt(&fifo, timeout);
if (upkt.Validate()) {
uint8_t *data = upkt.GetDataBuffer();
uint16_t len = upkt.GetDataSize();
IPADDR source = upkt.GetSourceAddress();
}

UDP Sockets Interface

The socket-based UDP interface provides a traditional function-based approach to UDP communication.

Receiving UDP Packets (Socket Method)

Setup Process**:

  1. Call CreateRxUdpSocket() to open listening socket (returns file descriptor)
  2. Call recvfrom() to receive packets (blocks by default)
  3. Optionally wrap recvfrom() in select() for timeout control

Sending UDP Packets (Socket Method)

Transmission Process**:

  1. Call CreateTxUdpSocket() to open socket (returns file descriptor)
  2. Call sendto() to transmit packets

UDP Socket Error Processing

These negative values are returned by UDP socket creation and operation functions to indicate specific error conditions. All successful operations return non-negative values (valid file descriptors >= 0 or byte counts >= 0).

#define UDP_ERR_NOSUCH_SOCKET (-1)
#define UDP_ERR_NOTOPEN_TO_WRITE (-2)
#define UDP_ERR_NOTOPEN_TO_READ (-3)

UDP_ERR_NOSUCH_SOCKET

Socket does not exist or operation failed

#define UDP_ERR_NOSUCH_SOCKET (-1)

Returned when:

  • Socket creation fails (port conflict, resource exhaustion)
  • Invalid socket descriptor used in operation
  • Socket was closed but still being referenced
  • System cannot allocate required resources

Common Scenarios:

Scenario 1: Port Already in Use

int sock1 = CreateRxUdpSocket(8080); // Success: sock1 = valid descriptor
int sock2 = CreateRxUdpSocket(8080); // Failure: returns UDP_ERR_NOSUCH_SOCKET
// Solution: Use different port or close sock1 first
int CreateRxUdpSocket(uint16_t listening_port)
Create receive-only UDP socket bound to specified port.

Scenario 2: Using Closed Socket

int sock = CreateRxUdpSocket(5000);
close(sock);
int result = sendto(sock, data, len, ip, port); // Returns UDP_ERR_NOSUCH_SOCKET
// Solution: Don't use socket after closing
int close(int fd)
Close the specified file descriptor and free the associated resources.

Scenario 3: Resource Exhaustion

// Creating too many sockets
for (int i = 0; i < 100; i++) {
int sock = CreateRxUdpSocket(5000 + i);
if (sock < 0) {
printf("Failed at socket %d: UDP_ERR_NOSUCH_SOCKET\r\n", i);
// Solution: Close unused sockets, reduce simultaneous socket count
break;
}
}

UDP_ERR_NOTOPEN_TO_WRITE

Socket not configured for sending operations

#define UDP_ERR_NOTOPEN_TO_WRITE
Socket not open for write.
Definition udp.h:4763

Returned when attempting to send data through a socket that was created in receive-only mode (using CreateRxUdpSocket()). The socket can only receive packets, not send them.

Common Scenarios:

Scenario 1: Sending on Receive-Only Socket

// Wrong: Create receive-only socket, then try to send
int sock = CreateRxUdpSocket(5000); // Receive-only!
uint8_t data[] = "Hello";
int result = sendto(sock, data, sizeof(data), destIP, 8080);
// Returns UDP_ERR_NOTOPEN_TO_WRITE
// Correct: Use transmit or bidirectional socket
int sock = CreateTxUdpSocket(destIP, 8080, 0); // Can send
int result = sendto(sock, data, sizeof(data), destIP, 8080); // Success
int CreateTxUdpSocket(const IPADDR &send_to_addr, uint16_t remote_port, uint16_t local_port)
Create transmit-only UDP socket for sending to specified destination.
Definition udp.h:5563

Scenario 2: Echo Server Without Bidirectional Socket

// Wrong: Echo server needs to send responses
int sock = CreateRxUdpSocket(5000); // Can only receive
uint8_t buf[512];
IPADDR clientIP;
uint16_t lp, rp;
int n = recvfrom(sock, buf, sizeof(buf), &clientIP, &lp, &rp); // OK
sendto(sock, buf, n, clientIP, rp); // Fails: UDP_ERR_NOTOPEN_TO_WRITE
// Correct: Use bidirectional socket
int sock = CreateRxTxUdpSocket(clientIP, rp, 5000); // Can send & receive
int n = recvfrom(sock, buf, sizeof(buf), &clientIP, &lp, &rp); // OK
sendto(sock, buf, n, clientIP, rp); // OK
int CreateRxTxUdpSocket(const IPADDR &send_to_addr, uint16_t send_to_remote_port, uint16_t local_port)
Create bidirectional UDP socket for both sending and receiving.
Definition udp.h:5748

Solution Patterns:

Pattern 1: Use Correct Socket Type

Pattern 2: Separate Sockets for Send/Receive

// Alternative: Use two separate sockets
int rxSock = CreateRxUdpSocket(5000); // For receiving
int txSock = CreateTxUdpSocket(destIP, destPort, 0); // For sending
// Receive on one socket
recvfrom(rxSock, buf, len, &srcIP, &lp, &rp);
// Send on different socket
sendto(txSock, data, dataLen, destIP, destPort);
Warning
This error does NOT mean the socket descriptor is invalid. The socket exists and may be used for receiving, just not sending.

UDP_ERR_NOTOPEN_TO_READ

Socket not configured for receiving operations

#define UDP_ERR_NOTOPEN_TO_READ (-3)

Returned when attempting to receive data from a socket that was created in transmit-only mode (using CreateTxUdpSocket()). The socket can only send packets, not receive them.

Common Scenarios:**

Scenario 1: Receiving on Transmit-Only Socket**

// Wrong: Create transmit-only socket, then try to receive
IPADDR serverIP = AsciiToIp("192.168.1.100");
int sock = CreateTxUdpSocket(serverIP, 8080, 0); // Transmit-only!
uint8_t buffer[512];
IPADDR srcIP;
uint16_t lp, rp;
int n = recvfrom(sock, buffer, sizeof(buffer), &srcIP, &lp, &rp);
// Returns UDP_ERR_NOTOPEN_TO_READ
// Correct: Use receive or bidirectional socket
int sock = CreateRxUdpSocket(localPort); // Can receive
int n = recvfrom(sock, buffer, sizeof(buffer), &srcIP, &lp, &rp); // Success

Scenario 2: Request/Response Without Bidirectional Socket**

// Wrong: Client expecting response but using transmit-only socket
IPADDR serverIP = AsciiToIp("10.0.1.50");
int sock = CreateTxUdpSocket(serverIP, 6000, 0); // Transmit-only
// Send request
uint8_t request[] = "GET /data";
sendto(sock, request, sizeof(request), serverIP, 6000); // OK
// Try to receive response
uint8_t response[512];
IPADDR respIP;
uint16_t lp, rp;
int n = recvfrom(sock, response, sizeof(response), &respIP, &lp, &rp);
// Fails: UDP_ERR_NOTOPEN_TO_READ
// Correct: Use bidirectional socket for request/response
int sock = CreateRxTxUdpSocket(serverIP, 6000, 0); // Can send & receive
sendto(sock, request, sizeof(request), serverIP, 6000); // OK
int n = recvfrom(sock, response, sizeof(response), &respIP, &lp, &rp); // OK

Scenario 3: DNS Query (Typical Request/Response)**

// Wrong approach
IPADDR dnsServer = AsciiToIp("8.8.8.8");
int sock = CreateTxUdpSocket(dnsServer, 53, 0); // Can't receive response!
// Correct approach
int sock = CreateRxTxUdpSocket(dnsServer, 53, 0); // Full duplex
// Send DNS query
uint8_t query[512];
int qlen = BuildDnsQuery(query, "example.com");
sendto(sock, query, qlen, dnsServer, 53);
// Receive DNS response
uint8_t response[512];
IPADDR srcIP;
uint16_t lp, rp;
int rlen = recvfrom(sock, response, sizeof(response), &srcIP, &lp, &rp);

Solution Patterns:**

Pattern 1: Choose Appropriate Socket Type**

Warning
This error does NOT mean the socket descriptor is invalid. The socket exists and may be used for sending, just not receiving.
Note
If you need truly one-way fire-and-forget communication, CreateTxUdpSocket() is more efficient than CreateRxTxUdpSocket() because it doesn't allocate receive buffers. However, most protocols benefit from at least basic acknowledgment, making bidirectional sockets the better choice.
See also
CreateRxUdpSocket() - For sockets that can receive
CreateRxTxUdpSocket() - For bidirectional communication
recvfrom() - Function that may return this error

Error Handling Pattern

Always check return values from UDP socket functions:

int sock = CreateRxUdpSocket(5000);
if (sock < 0) {
switch (sock) {
printf("Socket does not exist or creation failed\r\n");
break;
printf("Socket not configured for sending\r\n");
break;
printf("Socket not configured for receiving\r\n");
break;
default:
printf("Unknown error: %d\r\n", sock);
break;
}
return; // Don't proceed with invalid socket
}
// Safe to use socket
uint8_t buffer[1024];
IPADDR srcIP;
uint16_t lp, rp;
int bytesReceived = recvfrom(sock, buffer, sizeof(buffer), &srcIP, &lp, &rp);
#define UDP_ERR_NOTOPEN_TO_READ
Socket not open for read.
Definition udp.h:4764
#define UDP_ERR_NOSUCH_SOCKET
Socket does not exist.
Definition udp.h:4762

Common Causes and Solutions

UDP_ERR_NOSUCH_SOCKET

Causes:

  • Port already in use by another socket
  • System resource exhaustion (too many sockets)
  • Invalid socket descriptor passed to function
  • Socket was closed but still being referenced

Solutions:

  • Check that port is not already bound
  • Close unused sockets to free resources
  • Verify socket is valid before operations
  • Use different port numbers for different sockets
// BAD: Port conflict
int sock1 = CreateRxUdpSocket(8080);
int sock2 = CreateRxUdpSocket(8080); // Returns UDP_ERR_NOSUCH_SOCKET
// GOOD: Different ports or close first socket
int sock1 = CreateRxUdpSocket(8080);
// ... use sock1 ...
close(sock1);
int sock2 = CreateRxUdpSocket(8080); // Now succeeds

UDP_ERR_NOTOPEN_TO_WRITE

Causes

  • Attempting sendto() on receive-only socket (CreateRxUdpSocket)
  • Socket was created for receiving but not transmitting
  • Socket configuration flags incorrect

    Solutions:**

  • Use CreateTxUdpSocket() or CreateRxTxUdpSocket() for sending
  • Create separate sockets for different operations
  • Verify socket type matches intended operation
// BAD: Using receive-only socket for sending
int rxSock = CreateRxUdpSocket(5000);
sendto(rxSock, data, len, destIP, destPort); // Returns UDP_ERR_NOTOPEN_TO_WRITE
// GOOD: Use appropriate socket type
int txSock = CreateTxUdpSocket(destIP, destPort, 0);
sendto(txSock, data, len, destIP, destPort); // Succeeds
// OR: Use bidirectional socket
int rxtxSock = CreateRxTxUdpSocket(destIP, destPort, 5000);
sendto(rxtxSock, data, len, destIP, destPort); // Succeeds

UDP_ERR_NOTOPEN_TO_READ

Causes

  • Attempting recvfrom() on transmit-only socket (CreateTxUdpSocket)
  • Socket was created for sending but not receiving
  • Socket configuration flags incorrect

    Solutions:**

  • Use CreateRxUdpSocket() or CreateRxTxUdpSocket() for receiving
  • Create separate sockets for different operations
  • Verify socket type matches intended operation
// BAD: Using transmit-only socket for receiving
IPADDR serverIP = AsciiToIp("192.168.1.100");
int txSock = CreateTxUdpSocket(serverIP, 8080, 0);
recvfrom(txSock, buffer, len, &srcIP, &lp, &rp); // Returns UDP_ERR_NOTOPEN_TO_READ
// GOOD: Use appropriate socket type
int rxSock = CreateRxUdpSocket(8080);
recvfrom(rxSock, buffer, len, &srcIP, &lp, &rp); // Succeeds
// OR: Use bidirectional socket for request/response
int rxtxSock = CreateRxTxUdpSocket(serverIP, 8080, 0);
sendto(rxtxSock, request, reqLen, serverIP, 8080);
recvfrom(rxtxSock, buffer, len, &srcIP, &lp, &rp); // Both succeed

Error Checking Best Practices

1. Always Validate Socket Creation

int sock = CreateRxUdpSocket(port);
if (sock < 0) {
// Handle error appropriately
printf("Socket creation failed: %d\r\n", sock);
return ERROR_CODE; // Don't continue
}
// Safe to use sock

2. Check Operation Return Values

int bytesSent = sendto(sock, data, len, destIP, destPort);
if (bytesSent < 0) {
printf("Send failed: error %d\r\n", bytesSent);
} else if (bytesSent != len) {
printf("Warning: Partial send (%d of %d bytes)\r\n", bytesSent, len);
}

3. Defensive Programming

// Store error code in variable for debugging
int result = CreateRxUdpSocket(port);
if (result < 0) {
// Log detailed error information
printf("CreateRxUdpSocket(%d) failed with error %d at %s:%d\r\n",
port, result, __FILE__, __LINE__);
// Take appropriate recovery action
switch (result) {
// Maybe try alternative port
result = CreateRxUdpSocket(port + 1);
break;
// ... other cases ...
}
}

4. Resource Cleanup on Error

int sock1 = CreateRxUdpSocket(5000);
if (sock1 < 0) {
return ERROR_SOCKET1;
}
int sock2 = CreateRxUdpSocket(5001);
if (sock2 < 0) {
close(sock1); // Clean up first socket
return ERROR_SOCKET2;
}
// Both sockets valid
// ... use sockets ...
// Cleanup
close(sock1);
close(sock2);

Debugging Errors

When encountering UDP errors:

  1. Enable System Diagnostics
    void UserMain(void* pd) {
    init();
    EnableSystemDiagnostics(); // Shows resource usage
    // ... rest of code ...
    }
    void EnableSystemDiagnostics()
    Turn on the diagnostic reports from the config page.
  2. Check Resource Availability
    • Monitor socket count
    • Check buffer pool usage
    • Verify network interface status
  3. Test with Simple Cases
    • Start with single socket
    • Verify basic send/receive works
    • Add complexity incrementally
  4. Use Network Tools
    • Wireshark to capture packets
    • netcat (nc) to test connectivity
    • Verify firewall settings

Related Functions

Functions that may return these error codes:

UDP Sockets Example

This example demonstrates UDP communication using socket functions instead of the UDPPacket class.

UDP Sockets Send/Receive Example

Features:

  • Bidirectional UDP communication
  • Task-based receive handling
  • Main loop for sending
#include <init.h>
#include <stdlib.h>
#include <string.h>
#include <system.h>
#include <udp.h>
#include <utils.h>
const char *AppName = "UDP Sockets Example";
// Allocate stack space for the listen task
uint32_t UdpReceiveTaskStack[USER_TASK_STK_SIZE];
//
// UDP Receive Task
// Waits for incoming UDP packets and processes them
//
void UdpReceiveTask(void *pd)
{
int listenPort = (int)pd;
printf("UdpReceiveTask monitoring port %d\r\n", listenPort);
// Create UDP socket for receiving
int udpFd = CreateRxUdpSocket(listenPort);
if (udpFd <= 0)
{
printf("Error Creating UDP Listen Socket: %d\r\n", udpFd);
while (1)
{
OSTimeDly(TICKS_PER_SECOND);
}
}
else
{
printf("Listening for UDP packets on port %d\r\n", listenPort);
}
while (1)
{
IPADDR sourceIpAddress; // Packet source IP
uint16_t localPort; // Local port (destination)
uint16_t sourcePort; // Source port
char buffer[80];
int len = recvfrom(udpFd, (uint8_t *)buffer, 80,
&sourceIpAddress, &localPort, &sourcePort);
buffer[len] = '\0';
printf("\r\nReceived a UDP packet with %d bytes from: %I\r\n%s\r\n",
len, sourceIpAddress, buffer);
}
}
//
// User Main
//
void UserMain(void *pd)
{
int portNumber;
IPADDR destIpAddress;
char buffer[80];
init();
printf("Application: %s\r\nNNDK Revision: %s\r\n", AppName, GetReleaseTag());
// Get destination IP address
printf("Enter the UDP Server destination IP address: ");
gets(buffer);
destIpAddress = AsciiToIp(buffer);
printf("\r\n");
// Get port number (used for send and receive)
printf("Enter the source/destination port number: ");
gets(buffer);
portNumber = atoi(buffer);
printf("\r\n");
// Create UDP socket for sending
int udpFd = CreateTxUdpSocket(destIpAddress, portNumber, portNumber);
if (udpFd <= 0)
{
printf("Error Creating UDP Socket: %d\r\n", udpFd);
while (1)
{
OSTimeDly(TICKS_PER_SECOND);
}
}
else
{
printf("Sending/Receiving with host %I:%d\r\n", destIpAddress, portNumber);
}
// Create UDP receive task (higher priority for responsive reception)
OSTaskCreatewName(UdpReceiveTask,
(void *)portNumber,
&UdpReceiveTaskStack[USER_TASK_STK_SIZE],
UdpReceiveTaskStack,
MAIN_PRIO - 1,
"UDP Receive");
printf("Enter data and hit enter to send.\r\n");
// Main loop: send user input as UDP packets
while (1)
{
gets(buffer);
printf("\r\n");
printf("Sending \"%s\" using UDP to %I:%d\r\n", buffer, destIpAddress, portNumber);
sendto(udpFd, (uint8_t *)buffer, strlen(buffer), destIpAddress, portNumber);
printf("\r\n");
}
}

Socket Function Reference

Receiving**:

int udpFd = CreateRxUdpSocket(localPort);
IPADDR sourceIP;
uint16_t sourcePort, destPort;
char buffer[SIZE];
int len = recvfrom(udpFd, (uint8_t*)buffer, SIZE,
&sourceIP, &destPort, &sourcePort);

Sending**:

int udpFd = CreateTxUdpSocket(destIP, destPort, sourcePort);
sendto(udpFd, (uint8_t*)buffer, length, destIP, destPort);

UDP Socket Architecture

Socket-Based UDP Flow:
Receive Path: Send Path:
┌──────────────────┐ ┌───────────────────┐
│ CreateRxUdpSocket│ │ CreateTxUdpSocket
│ (port) │ │ (ip, dport, sport)│
└────────┬─────────┘ └────────┬──────────┘
│ │
v v
┌──────────────────┐ ┌──────────────────┐
recvfrom() │ │ sendto() │
│ [BLOCKING] │ │ (immediate) │
└────────┬─────────┘ └────────┬─────────┘
│ │
v v
┌──────────────────┐ ┌──────────────────┐
│ Extract data │ │ Packet sent │
│ from buffer │ │ to network │
└──────────────────┘ └──────────────────┘

Best Practices Summary

General Guidelines

  1. Protocol Selection:
    • Choose TCP for reliability and ordered delivery
    • Choose UDP for speed and efficiency
    • Consider application-layer reliability over UDP when appropriate
  2. Resource Management:
    • Always close sockets when done
    • Check return values from all network functions
    • Handle connection errors gracefully
  3. Task Architecture:
    • Use separate tasks for listening/receiving
    • Set appropriate task priorities
    • Consider using select() for multiple connections
  4. Buffer Management:
    • Allocate adequate buffer sizes
    • Null-terminate string data
    • Use static buffers in tasks to save stack space
  5. Error Handling:
    • Check socket creation return values
    • Handle connection failures
    • Implement timeout mechanisms

Performance Optimization

  • Use select() for multiple connections (TCP)
  • Consider OS_FIFO size for UDP packet bursts
  • Set appropriate task priorities for responsive I/O
  • Use ReadWithTimeout() for connection management

Security Considerations

  • Validate all received data
  • Implement authentication when needed
  • Use random source port numbers
  • Consider connection limits for servers