TCP Sockets
TCP sockets provide reliable, ordered communication over IP network sockets and have built-in protocols for handling packet acknowledgement as well as transmission speed / bandwidth adjustment.
TCP sockets cannot be used with multicast (many to one, one to many).
API Reference
Header File
Classes
-
class TcpSocket : public espp::Socket
Class for managing sending and receiving data using TCP/IP. Can be used to create client or server sockets.
TCP Client Example
espp::TcpSocket client_socket({}); client_socket.connect({.ip_address = server_address, .port = port}); // 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; }); client_socket.transmit(data); 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();
TCP Server Example
std::string server_address = "127.0.0.1"; size_t port = 5000; int max_connections = 1; espp::TcpSocket server_socket({.log_level = espp::Logger::Verbosity::WARN}); server_socket.bind(port); server_socket.listen(max_connections); auto server_task_fn = [&server_socket](auto &m, auto &cv) -> bool { static std::unique_ptr<espp::TcpSocket> client_socket; if (!client_socket) { client_socket = server_socket.accept(); if (client_socket) { auto info = client_socket->get_remote_info(); fmt::print("Server accepted connection from: {}\n", info); } } if (client_socket) { std::vector<uint8_t> data; size_t max_receive_size = 1024; if (client_socket->receive(data, max_receive_size)) { fmt::print("Server received: {}\n", data); } } { std::unique_lock<std::mutex> lock(m); cv.wait_for(lock, 10ms); } // don't want to stop the task return false; }; auto server_task_config = espp::Task::Config{ .callback = server_task_fn, .task_config = { .name = "TcpServer", .stack_size_bytes = 6 * 1024, }, }; auto server_task = espp::Task::make_unique(server_task_config); server_task->start();
TCP Client Response Example
espp::TcpSocket client_socket({.log_level = espp::Logger::Verbosity::WARN}); client_socket.connect({ .ip_address = server_address, .port = port, }); // 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 transmit_config = espp::TcpSocket::TransmitConfig{ .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.transmit(data, transmit_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();
TCP Server Response Example
std::string server_address = "127.0.0.1"; size_t port = 5000; int max_connections = 1; espp::TcpSocket server_socket({.log_level = espp::Logger::Verbosity::WARN}); server_socket.bind(port); server_socket.listen(max_connections); auto server_task_fn = [&server_socket](auto &m, auto &cv) -> bool { static std::unique_ptr<espp::TcpSocket> client_socket; if (!client_socket) { client_socket = server_socket.accept(); if (client_socket) { auto info = client_socket->get_remote_info(); fmt::print("Server accepted connection from: {}\n", info); } } if (client_socket) { std::vector<uint8_t> data; size_t max_receive_size = 1024; if (client_socket->receive(data, max_receive_size)) { fmt::print("Server received: {}\n", data); // reverse the data std::reverse(data.begin(), data.end()); // and send it back client_socket->transmit(data); } } { std::unique_lock<std::mutex> lock(m); cv.wait_for(lock, 10ms); } // don't want to stop the task return false; }; auto server_task_config = espp::Task::Config{ .callback = server_task_fn, .task_config = { .name = "TcpServer", .stack_size_bytes = 6 * 1024, }, }; auto server_task = espp::Task::make_unique(server_task_config); server_task->start();
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 TcpSocket(const espp::TcpSocket::Config &config)
Initialize the socket and associated resources.
Note
Enables keepalive on the socket.
- Parameters
config – Config for the socket.
-
~TcpSocket()
Tear down any resources associted with the socket.
-
void reinit()
Reinitialize the socket, cleaning it up if first it is already initalized.
-
void close()
Close the socket.
-
bool is_connected() const
Check if the socket is connected to a remote endpoint.
- Returns
true if the socket is connected to a remote endpoint.
-
bool connect(const espp::TcpSocket::ConnectConfig &connect_config)
Open a connection to the remote TCP server.
- Parameters
connect_config – ConnectConfig struct describing the server endpoint.
- Returns
true if the client successfully connected to the server.
-
const espp::Socket::Info &get_remote_info() const
Get the remote endpoint info.
- Returns
The remote endpoint info.
-
bool transmit(const std::vector<uint8_t> &data, const espp::TcpSocket::TransmitConfig &transmit_config = espp::TcpSocket::TransmitConfig::Default())
Send data to the endpoint already connected to by TcpSocket::connect. 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.
- Parameters
data – vector of bytes to send to the remote endpoint.
transmit_config – TransmitConfig struct indicating whether to wait for a response.
- Returns
true if the data was sent, false otherwise.
-
bool transmit(const std::vector<char> &data, const espp::TcpSocket::TransmitConfig &transmit_config = espp::TcpSocket::TransmitConfig::Default())
Send data to the endpoint already connected to by TcpSocket::connect. 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.
- Parameters
data – vector of bytes to send to the remote endpoint.
transmit_config – TransmitConfig struct indicating whether to wait for a response.
- Returns
true if the data was sent, false otherwise.
-
bool transmit(std::string_view data, const espp::TcpSocket::TransmitConfig &transmit_config = espp::TcpSocket::TransmitConfig::Default())
Send data to the endpoint already connected to by TcpSocket::connect. 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.
- Parameters
data – string view of bytes to send to the remote endpoint.
transmit_config – TransmitConfig struct indicating whether to wait for a response.
- Returns
true if the data was sent, false otherwise.
-
bool receive(std::vector<uint8_t> &data, size_t max_num_bytes)
Call read on the socket, assuming it has already been configured appropriately.
- Parameters
data – Vector of bytes of received data.
max_num_bytes – Maximum number of bytes to receive.
- Returns
true if successfully received, false otherwise.
-
size_t receive(uint8_t *data, size_t max_num_bytes)
Call read on the socket, assuming it has already been configured appropriately.
Note
This function will block until max_num_bytes are received or the receive timeout is reached.
Note
The data pointed to by data must be at least max_num_bytes in size.
- Parameters
data – Pointer to buffer to receive data.
max_num_bytes – Maximum number of bytes to receive.
- Returns
Number of bytes received.
-
bool bind(int port)
Bind the socket as a server on
port
.- Parameters
port – The port to which to bind the socket.
- Returns
true if the socket was bound.
-
bool listen(int max_pending_connections)
Listen for incoming client connections.
See also
See also
Note
Must be called after bind and before accept.
- Parameters
max_pending_connections – Max number of allowed pending connections.
- Returns
True if socket was able to start listening.
-
std::unique_ptr<espp::TcpSocket> accept()
Accept an incoming connection.
Note
Blocks until a connection is accepted.
Note
Must be called after listen.
Note
This function will block until a connection is accepted.
- Returns
A unique pointer to a TcpClientSession if a connection was accepted, nullptr 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 TransmitConfig
Config struct for sending data to a remote TCP socket.
Note
This is only used when waiting for a response from the remote.
Public Members
-
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.
-
bool wait_for_response = false