UDP Sockets
UDP sockets provide unreliable, unordered communication over IP network sockets.
UDP sockets can be used in unicast (point to point), multicast (one to many and many to one), and broadcast (one to all).
API Reference
Header File
Classes
-
class UdpSocket : public espp::Socket
Class for managing sending and receiving data using UDP/IP. Can be used to create client or server sockets.
See https://github.com/espressif/esp-idf/tree/master/examples/protocols/sockets/udp_multicast for more information on udp multicast sockets.
UDP Client Example
espp::UdpSocket client_socket({}); // create thread for sending data using the socket auto client_task_fn = [&server_address, &client_socket, &port](auto &, auto &) { static size_t iterations = 0; std::vector<uint8_t> data{0, 1, 2, 3, 4}; std::transform(data.begin(), data.end(), data.begin(), [](const auto &d) { return d + iterations; }); auto send_config = espp::UdpSocket::SendConfig{.ip_address = server_address, .port = port}; client_socket.send(data, send_config); iterations++; std::this_thread::sleep_for(1s); // don't want to stop the task return false; }; auto client_task = espp::Task::make_unique({.callback = client_task_fn, .task_config = {.name = "Client Task", .stack_size_bytes = 5 * 1024}}); client_task->start();
UDP Server Example
std::string server_address = "127.0.0.1"; size_t port = 5000; espp::UdpSocket server_socket({.log_level = espp::Logger::Verbosity::WARN}); auto server_task_config = espp::Task::BaseConfig{ .name = "UdpServer", .stack_size_bytes = 6 * 1024, }; auto server_config = espp::UdpSocket::ReceiveConfig{ .port = port, .buffer_size = 1024, .on_receive_callback = [](auto &data, auto &source) -> auto{fmt::print("Server received: {}\n" " from source: {}\n", data, source); return std::nullopt; } }; server_socket.start_receiving(server_task_config, server_config);
UDP Client Response Example
espp::UdpSocket client_socket({.log_level = espp::Logger::Verbosity::WARN}); // create threads auto client_task_fn = [&server_address, &client_socket, &port](auto &, auto &) { static size_t iterations = 0; std::vector<uint8_t> data{0, 1, 2, 3, 4}; std::transform(data.begin(), data.end(), data.begin(), [](const auto &d) { return d + iterations; }); auto send_config = espp::UdpSocket::SendConfig{ .ip_address = server_address, .port = port, .wait_for_response = true, .response_size = 128, .on_response_callback = [](auto &response) { fmt::print("Client received: {}\n", response); }, }; // NOTE: now this call blocks until the response is received client_socket.send(data, send_config); iterations++; std::this_thread::sleep_for(1s); // don't want to stop the task return false; }; auto client_task = espp::Task::make_unique({.callback = client_task_fn, .task_config = {.name = "Client Task", .stack_size_bytes = 5 * 1024}}); client_task->start();
UDP Server Response Example
std::string server_address = "127.0.0.1"; size_t port = 5000; espp::UdpSocket server_socket({.log_level = espp::Logger::Verbosity::WARN}); auto server_task_config = espp::Task::BaseConfig{.name = "UdpServer", .stack_size_bytes = 6 * 1024}; auto server_config = espp::UdpSocket::ReceiveConfig{ .port = port, .buffer_size = 1024, .on_receive_callback = [](auto &data, auto &source) -> auto{fmt::print("Server received: {}\n" " from source: {}\n", data, source); // reverse the data std::reverse(data.begin(), data.end()); // and send it back return data; } } ; server_socket.start_receiving(server_task_config, server_config);
UDP Multicast Client Example
espp::UdpSocket client_socket({}); // create threads auto client_task_fn = [&client_socket, &port, &multicast_group](auto &, auto &) { static size_t iterations = 0; std::vector<uint8_t> data{0, 1, 2, 3, 4}; std::transform(data.begin(), data.end(), data.begin(), [](const auto &d) { return d + iterations; }); auto send_config = espp::UdpSocket::SendConfig{.ip_address = multicast_group, .port = port, .is_multicast_endpoint = true, .wait_for_response = true, .response_size = 128, .on_response_callback = [](auto &response) { fmt::print("Client received: {}\n", response); }}; // NOTE: now this call blocks until the response is received client_socket.send(data, send_config); iterations++; std::this_thread::sleep_for(1s); // don't want to stop the task return false; }; auto client_task = espp::Task::make_unique({.callback = client_task_fn, .task_config = {.name = "Client Task", .stack_size_bytes = 5 * 1024}}); client_task->start();
UDP Multicast Server Example
std::string multicast_group = "239.1.1.1"; size_t port = 5000; espp::UdpSocket server_socket({.log_level = espp::Logger::Verbosity::WARN}); auto server_task_config = espp::Task::BaseConfig{ .name = "UdpServer", .stack_size_bytes = 6 * 1024, }; auto server_config = espp::UdpSocket::ReceiveConfig{ .port = port, .buffer_size = 1024, .is_multicast_endpoint = true, .multicast_group = multicast_group, .on_receive_callback = [](auto &data, auto &source) -> auto{fmt::print("Server received: {}\n" " from source: {}\n", data, source); // reverse the data std::reverse(data.begin(), data.end()); // and send it back return data; } } ; server_socket.start_receiving(server_task_config, server_config);
Public Types
- std::function< std::optional< std::vector< uint8_t > >std::vector< uint8_t > &data, const Info &sender_info)> receive_callback_fn
Callback function to be called when receiving data from a client.
- Param data
Byte array of data received from client
- Param sender_info
Sender information (address, port)
- Return
std::optional<std::vector<uint8_t>> optional data to return to sender.
-
typedef std::function<void(std::vector<uint8_t> &data)> response_callback_fn
Callback function to be called with data returned after transmitting data to a server.
- Param data
The data that the server responded with
Public Functions
-
explicit UdpSocket(const Config &config)
Initialize the socket and associated resources.
- Parameters
config – Config for the socket.
-
~UdpSocket()
Tear down any resources associted with the socket.
-
bool send(const std::vector<uint8_t> &data, const SendConfig &send_config)
Send data to the endpoint specified by the send_config. Can be configured to multicast (within send_config) and can be configured to block waiting for a response from the remote.
If response is requested, a callback can be provided in send_config which will be provided the response data for processing.
Note
in the case of multicast, it will block only until the first response.
- Parameters
data – vector of bytes to send to the remote endpoint.
send_config – SendConfig struct indicating where to send and whether to wait for a response.
- Returns
true if the data was sent, false otherwise.
-
bool send(std::string_view data, const SendConfig &send_config)
Send data to the endpoint specified by the send_config. Can be configured to multicast (within send_config) and can be configured to block waiting for a response from the remote.
If response is requested, a callback can be provided in send_config which will be provided the response data for processing.
Note
in the case of multicast, it will block only until the first response.
- Parameters
data – String view of bytes to send to the remote endpoint.
send_config – SendConfig struct indicating where to send and whether to wait for a response.
- Returns
true if the data was sent, false otherwise.
-
bool receive(size_t max_num_bytes, std::vector<uint8_t> &data, Socket::Info &remote_info)
Call recvfrom on the socket, assuming it has already been configured appropriately.
- Parameters
max_num_bytes – Maximum number of bytes to receive.
data – Vector of bytes of received data.
remote_info – Socket::Info containing the sender’s information. This will be populated with the information about the sender.
- Returns
true if successfully received, false otherwise.
-
bool start_receiving(Task::BaseConfig &task_config, const ReceiveConfig &receive_config)
Configure a server socket and start a thread to continuously receive and handle data coming in on that socket.
- Parameters
task_config – Task::BaseConfig struct for configuring the receive task.
receive_config – ReceiveConfig struct with socket and callback info.
- Returns
true if the socket was created and task was started, false otherwise.
-
bool is_valid() const
Is the socket valid.
- Returns
true if the socket file descriptor is >= 0.
-
std::optional<Info> get_ipv4_info()
Get the Socket::Info for the socket.
This will call getsockname() on the socket to get the sockaddr_storage structure, and then fill out the Socket::Info structure.
- Returns
Socket::Info for the socket.
-
bool set_receive_timeout(const std::chrono::duration<float> &timeout)
Set the receive timeout on the provided socket.
- Parameters
timeout – requested timeout, must be > 0.
- Returns
true if SO_RECVTIMEO was successfully set.
-
bool enable_reuse()
Allow others to use this address/port combination after we’re done with it.
- Returns
true if SO_REUSEADDR and SO_REUSEPORT were successfully set.
-
bool make_multicast(uint8_t time_to_live = 1, uint8_t loopback_enabled = true)
Configure the socket to be multicast (if time_to_live > 0). Sets the IP_MULTICAST_TTL (number of multicast hops allowed) and optionally configures whether this node should receive its own multicast packets (IP_MULTICAST_LOOP).
- Parameters
time_to_live – number of multicast hops allowed (TTL).
loopback_enabled – Whether to receive our own multicast packets.
- Returns
true if IP_MULTICAST_TTL and IP_MULTICAST_LOOP were set.
-
bool add_multicast_group(const std::string &multicast_group)
If this is a server socket, add it to the provided the multicast group.
See https://en.wikipedia.org/wiki/Multicast_address for more information.
Note
Multicast groups must be Class D addresses (224.0.0.0 to 239.255.255.255)
- Parameters
multicast_group – multicast group to join.
- Returns
true if IP_ADD_MEMBERSHIP was successfully set.
-
int select(const std::chrono::microseconds &timeout)
Select on the socket for read events.
- Parameters
timeout – how long to wait for an event.
- Returns
number of events that occurred.
-
inline const std::string &get_name() const
Get the name of the component
Note
This is the tag of the logger
- Returns
A const reference to the name of the component
-
inline void set_log_tag(const std::string_view &tag)
Set the tag for the logger
- Parameters
tag – The tag to use for the logger
-
inline espp::Logger::Verbosity get_log_level() const
Get the log level for the logger
See also
See also
- Returns
The verbosity level of the logger
-
inline void set_log_level(espp::Logger::Verbosity level)
Set the log level for the logger
See also
See also
- Parameters
level – The verbosity level to use for the logger
-
inline void set_log_verbosity(espp::Logger::Verbosity level)
Set the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls set_log_level
- Parameters
level – The verbosity level to use for the logger
-
inline espp::Logger::Verbosity get_log_verbosity() const
Get the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls get_log_level
- Returns
The verbosity level of the logger
-
inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
Set the rate limit for the logger
See also
Note
Only calls to the logger that have _rate_limit suffix will be rate limited
- Parameters
rate_limit – The rate limit to use for the logger
Public Static Functions
-
static bool is_valid_fd(sock_type_t socket_fd)
Is the socket valid.
- Parameters
socket_fd – Socket file descriptor.
- Returns
true if the socket file descriptor is >= 0.
-
struct Config
-
struct ReceiveConfig
Public Members
-
size_t port
Port number to bind to / receive from.
-
size_t buffer_size
Max size of data we can receive at one time.
-
bool is_multicast_endpoint = {false}
Whether this should be a multicast endpoint.
-
std::string multicast_group{""}
If this is a multicast endpoint, this is the group it belongs to.
-
size_t port
-
struct SendConfig
Public Members
-
std::string ip_address
Address to send data to.
-
size_t port
Port number to send data to.
-
bool is_multicast_endpoint = {false}
Whether this should be a multicast endpoint.
-
bool wait_for_response = {false}
Whether to wait for a response from the remote or not.
-
size_t response_size{0}
If waiting for a response, this is the maximum size response we will receive.
-
espp::Socket::response_callback_fn on_response_callback{nullptr}
If waiting for a response, this is an optional handler which is provided the response data.
-
std::chrono::duration<float> response_timeout = std::chrono::duration<float>(0.5f)
If waiting for a response, this is the maximum timeout to wait.
-
std::string ip_address