jsocketpp 1.0
A cross-platform C++20 socket library.
Loading...
Searching...
No Matches

Classes and functions for UDP datagram networking. More...

Collaboration diagram for UDP Sockets:

Classes

struct  jsocketpp::DatagramReadOptions
 Options controlling a single UDP receive operation. More...
struct  jsocketpp::DatagramReadResult
 Telemetry data about a single UDP datagram receive operation. More...
struct  jsocketpp::ReadExactOptions
 Policy for enforcing an exact-byte receive on a single UDP datagram. More...
class  jsocketpp::DatagramPacket
 Represents a UDP datagram packet, encapsulating both payload and addressing information. More...
class  jsocketpp::DatagramSocket
 Cross-platform UDP socket class with Java-style interface. More...
class  jsocketpp::MulticastSocket
 Cross-platform multicast UDP socket class (IPv4/IPv6). More...

Enumerations

enum class  jsocketpp::DatagramReceiveMode : std::uint8_t { jsocketpp::DatagramReceiveMode::NoPreflight = 0 , jsocketpp::DatagramReceiveMode::PreflightSize = 1 , jsocketpp::DatagramReceiveMode::PreflightMax = 2 }
 Receive-time sizing policy for UDP datagrams. More...
enum class  jsocketpp::Direction : std::uint8_t { jsocketpp::Direction::Read , jsocketpp::Direction::Write , jsocketpp::Direction::ReadWrite }
 I/O readiness selector used by waitReady(). More...

Functions

bool jsocketpp::DatagramPacket::hasDestination () const noexcept
 Report whether this packet specifies an explicit destination (address + port).
 jsocketpp::DatagramSocket::DatagramSocket (Port localPort=0, std::string_view localAddress="", std::optional< std::size_t > recvBufferSize=std::nullopt, std::optional< std::size_t > sendBufferSize=std::nullopt, std::optional< std::size_t > internalBufferSize=std::nullopt, bool reuseAddress=true, int soRecvTimeoutMillis=-1, int soSendTimeoutMillis=-1, bool nonBlocking=false, bool dualStack=true, bool autoBind=true, bool autoConnect=false, std::string_view remoteAddress="", Port remotePort=0, int connectTimeoutMillis=-1)
 Creates a UDP socket, optionally binds to a local address, and optionally connects to a remote peer.
 jsocketpp::DatagramSocket::~DatagramSocket () noexcept override
 Destructor for DatagramSocket. Ensures socket resources are released.
 jsocketpp::DatagramSocket::DatagramSocket (const DatagramSocket &)=delete
 Copy constructor (deleted) for DatagramSocket.
DatagramSocketjsocketpp::DatagramSocket::operator= (const DatagramSocket &)=delete
 Copy assignment operator (deleted) for DatagramSocket.
 jsocketpp::DatagramSocket::DatagramSocket (DatagramSocket &&rhs) noexcept
 Move constructor for DatagramSocket.
DatagramSocketjsocketpp::DatagramSocket::operator= (DatagramSocket &&rhs) noexcept
 Move assignment operator for DatagramSocket.
void jsocketpp::DatagramSocket::bind ()
 Binds the datagram socket to all available interfaces on an ephemeral port.
void jsocketpp::DatagramSocket::bind (Port localPort)
 Binds the datagram socket to a specific local port on all network interfaces.
void jsocketpp::DatagramSocket::bind (std::string_view localAddress, Port localPort)
 Binds the datagram socket to a specific local IP address and port.
bool jsocketpp::DatagramSocket::isBound () const noexcept
 Indicates whether the datagram socket has been explicitly bound to a local address or port.
void jsocketpp::DatagramSocket::connect (std::string_view host, Port port, int timeoutMillis)
 Connect this UDP socket to a default peer (set the default destination).
void jsocketpp::DatagramSocket::disconnect ()
 Disconnect this UDP socket from its current default peer.
bool jsocketpp::DatagramSocket::isConnected () const noexcept
 Indicates whether the datagram socket is connected to a specific remote peer.
std::string jsocketpp::DatagramSocket::getLocalIp (bool convertIPv4Mapped)
 Return the local interface IP address for this UDP socket.
Port jsocketpp::DatagramSocket::getLocalPort ()
 Return the local UDP port this socket is bound to.
std::string jsocketpp::DatagramSocket::getLocalSocketAddress (bool convertIPv4Mapped)
 Return the local endpoint as a single "ip:port" string.
std::string jsocketpp::DatagramSocket::getRemoteIp (bool convertIPv4Mapped) const
 Return the remote peer IP address for this socket.
Port jsocketpp::DatagramSocket::getRemotePort () const
 Return the remote peer UDP port for this socket.
std::string jsocketpp::DatagramSocket::getRemoteSocketAddress (bool convertIPv4Mapped) const
 Return the remote endpoint as a single "ip:port" string.
void jsocketpp::DatagramSocket::write (std::string_view message) const
 Send one UDP datagram to the currently connected peer (no pre-wait).
template<typename T>
void jsocketpp::DatagramSocket::write (const T &value) const
 Send one UDP datagram whose payload is the raw object representation of value.
void jsocketpp::DatagramSocket::write (std::span< const std::byte > data) const
 Send one UDP datagram to the connected peer from a raw byte span (no pre-wait).
void jsocketpp::DatagramSocket::writeAll (std::string_view message) const
 Send one UDP datagram to the connected peer, waiting indefinitely for writability.
template<typename T>
void jsocketpp::DatagramSocket::writePrefixed (const std::string_view payload) const
 Send a length-prefixed UDP datagram to the connected peer from text bytes (no pre-wait).
template<typename T>
void jsocketpp::DatagramSocket::writePrefixed (const std::span< const std::byte > payload) const
 Send a length-prefixed UDP datagram to the connected peer from a byte span (no pre-wait).
template<typename T>
void jsocketpp::DatagramSocket::writePrefixedTo (const std::string_view host, const Port port, const std::string_view payload) const
 Send a length-prefixed UDP datagram to (host, port) from text bytes (unconnected path).
template<typename T>
void jsocketpp::DatagramSocket::writePrefixedTo (const std::string_view host, const Port port, const std::span< const std::byte > payload) const
 Send a length-prefixed UDP datagram to (host, port) from a byte span (unconnected path).
void jsocketpp::DatagramSocket::writev (std::span< const std::string_view > buffers) const
 Send one UDP datagram to the connected peer by concatenating multiple fragments (no pre-wait).
void jsocketpp::DatagramSocket::writevAll (std::span< const std::string_view > buffers) const
 Send one UDP datagram to the connected peer by concatenating multiple fragments, waiting indefinitely.
void jsocketpp::DatagramSocket::writeFrom (const void *data, std::size_t len) const
 Send one UDP datagram to the connected peer from a raw memory buffer (no pre-wait).
void jsocketpp::DatagramSocket::writeWithTimeout (std::string_view data, int timeoutMillis) const
 Send one UDP datagram to the connected peer, waiting up to timeoutMillis for writability.
void jsocketpp::DatagramSocket::write (const DatagramPacket &packet)
 Send one UDP datagram using a packet’s buffer and optional explicit destination.
void jsocketpp::DatagramSocket::writeTo (std::string_view host, Port port, std::string_view message)
 Send one unconnected UDP datagram to (host, port) from text bytes (no pre-wait).
void jsocketpp::DatagramSocket::writeTo (std::string_view host, Port port, std::span< const std::byte > data)
 Send one unconnected UDP datagram to (host, port) from a raw byte span (no pre-wait).
template<typename T>
void jsocketpp::DatagramSocket::writeTo (const std::string_view host, const Port port, const T &value) const
 Send one unconnected UDP datagram to (host, port) containing the raw bytes of value.
DatagramReadResult jsocketpp::DatagramSocket::read (DatagramPacket &packet, const DatagramReadOptions &opts) const
 Read one UDP datagram into a DatagramPacket with optional growth/shrink and strict truncation policy.
DatagramReadResult jsocketpp::DatagramSocket::readInto (void *buffer, std::size_t len, const DatagramReadOptions &opts={}) const
 Read one UDP datagram into a caller-provided buffer with explicit truncation policy.
DatagramReadResult jsocketpp::DatagramSocket::readInto (std::span< char > out, const DatagramReadOptions &opts={}) const
 Read one UDP datagram into a caller-provided span (zero allocation) with explicit truncation policy.
template<typename T, std::enable_if_t< detail::is_dynamic_buffer_v< T >, int > = 0>
jsocketpp::DatagramSocket::read (const DatagramReadOptions &opts={}, std::size_t minCapacity=DefaultDatagramReceiveSize) const
 Read one UDP datagram into a dynamically resizable, contiguous byte container (zero-copy into caller storage).
template<typename T, std::enable_if_t< detail::is_fixed_buffer_v< T >, int > = 0>
jsocketpp::DatagramSocket::read (const DatagramReadOptions &opts={}) const
 Read one UDP datagram into a fixed-size, contiguous byte container (zero allocation).
template<typename T>
DatagramReadResult jsocketpp::DatagramSocket::readFrom (T &buffer, std::string *senderAddr, Port *senderPort, const DatagramReadOptions &opts) const
 Read one UDP datagram into a caller-provided byte container and optionally return the sender address/port.
DatagramReadResult jsocketpp::DatagramSocket::readExact (void *buffer, std::size_t exactLen, const ReadExactOptions &opts={}) const
 Receive exactly exactLen bytes from a single UDP datagram into buffer, with strict policy control.
DatagramReadResult jsocketpp::DatagramSocket::readExact (std::span< char > out, const ReadExactOptions &opts={}) const
 Span overload of readExact(...) (derives exactLen from out.size()).
template<typename T>
DatagramReadResult jsocketpp::DatagramSocket::readExact (T &buffer, const std::size_t exactLen, const ReadExactOptions &opts={}) const
 Receive exactly exactLen bytes from a single UDP datagram into a contiguous byte container.
std::size_t jsocketpp::DatagramSocket::readAtMost (std::span< char > out, const DatagramReadOptions &opts={}) const
 Read up to out.size() bytes from the next UDP datagram into a caller-provided buffer (no allocation).
std::string jsocketpp::DatagramSocket::readAvailable () const
 Receive the next UDP datagram and return its payload as a string, attempting to avoid truncation.
std::size_t jsocketpp::DatagramSocket::readAvailable (std::span< char > out, const DatagramReadOptions &opts={}) const
 Receive the entire next UDP datagram into a caller-provided buffer, with explicit truncation policy.
std::size_t jsocketpp::DatagramSocket::readIntoExact (void *buffer, std::size_t len) const
 Strict exact-length UDP receive into a caller-provided buffer (single datagram).
std::string jsocketpp::DatagramSocket::readAtMostWithTimeout (std::size_t n, int timeoutMillis) const
 Read up to n bytes from the next UDP datagram, waiting up to timeoutMillis for data.
template<typename T, std::enable_if_t< std::is_integral_v< T > &&std::is_unsigned_v< T > &&std::is_trivially_copyable_v< T >, int > = 0>
std::string jsocketpp::DatagramSocket::readPrefixed (std::size_t maxPayloadLen=MaxDatagramPayloadSafe, const std::endian prefixEndian=std::endian::big) const
 Read a length-prefixed UDP datagram and return the payload (prefix type T).
void jsocketpp::DatagramSocket::discard (const DatagramReadOptions &opts={}) const
 Discard the next UDP datagram without copying it out.
void jsocketpp::DatagramSocket::discardExact (std::size_t n, const DatagramReadOptions &opts={}) const
 Discard the next UDP datagram only if its payload size is exactly n bytes.
DatagramReadResult jsocketpp::DatagramSocket::readv (std::span< BufferView > buffers, const DatagramReadOptions &opts={}) const
 Scatter-gather receive: read one UDP datagram into multiple non-contiguous buffers.
DatagramReadResult jsocketpp::DatagramSocket::readvAll (std::span< BufferView > buffers, const DatagramReadOptions &opts={}) const
 Scatter-gather receive that guarantees the entire next datagram fits the provided buffers.
std::size_t jsocketpp::DatagramSocket::readvAllBytes (std::span< BufferView > buffers, const DatagramReadOptions &opts={}) const
 Back-compat convenience returning only the number of bytes copied.
DatagramReadResult jsocketpp::DatagramSocket::readvAtMostWithTimeout (std::span< BufferView > buffers, int timeoutMillis, const DatagramReadOptions &opts={}) const
 Scatter-gather, best-effort read of the next datagram with a per-call timeout.
std::size_t jsocketpp::DatagramSocket::readvAtMostWithTimeout (std::span< BufferView > buffers, int timeoutMillis) const
 Convenience wrapper returning only the number of bytes read.
DatagramReadResult jsocketpp::DatagramSocket::readvAllWithTotalTimeout (std::span< BufferView > buffers, int totalTimeoutMillis, const DatagramReadOptions &opts={}) const
 Scatter-gather, strict no-truncation receive with a per-call total timeout.
std::size_t jsocketpp::DatagramSocket::readvAllWithTotalTimeoutBytes (std::span< BufferView > buffers, int totalTimeoutMillis, const DatagramReadOptions &opts={}) const
 Convenience wrapper returning only the number of bytes copied.
DatagramReadResult jsocketpp::DatagramSocket::peek (DatagramPacket &packet, bool allowResize=true, const DatagramReadOptions &opts={}) const
 Peek at the next UDP datagram without consuming it (single receive with MSG_PEEK).
bool jsocketpp::DatagramSocket::hasPendingData (int timeoutMillis) const
 Check if the socket is readable within a timeout (no data is consumed).
std::optional< int > jsocketpp::DatagramSocket::getMTU () const
 Retrieves the Maximum Transmission Unit (MTU) of the local interface associated with the socket.
void jsocketpp::DatagramSocket::waitReady (Direction dir, int timeoutMillis) const
 Block until the socket is ready for I/O or a timeout occurs.
void jsocketpp::DatagramSocket::setInternalBufferSize (std::size_t newLen)
 Sets the size of the internal buffer used for string-based UDP receive operations.
void jsocketpp::DatagramSocket::close ()
 Closes the datagram socket and releases its underlying system resources.
bool jsocketpp::DatagramSocket::isValid () const noexcept
 Checks whether the datagram socket is valid and ready for use.
bool jsocketpp::DatagramSocket::isClosed () const noexcept
 Checks whether the datagram socket has been closed or is otherwise invalid.
std::optional< std::pair< sockaddr_storage, socklen_t > > jsocketpp::DatagramSocket::getLastPeerSockAddr () const
 Retrieves the raw socket address of the last known remote peer.
std::size_t jsocketpp::DatagramSocket::readIntoBuffer (char *buf, std::size_t len, DatagramReceiveMode mode, int recvFlags, sockaddr_storage *outSrc, socklen_t *outSrcLen, std::size_t *outDatagramSz, bool *outTruncated) const
 Low-level, single-recv primitive that copies one UDP datagram into a caller buffer.
void jsocketpp::DatagramSocket::cleanup ()
 Internal helper that releases socket resources and resets all internal state.
void jsocketpp::DatagramSocket::cleanupAndThrow (int errorCode)
 Releases all socket resources and throws a SocketException with the given error code.
void jsocketpp::DatagramSocket::cleanupAndRethrow ()
 Cleans up the datagram socket and rethrows the currently active exception.
std::size_t jsocketpp::DatagramSocket::chooseReceiveSize () const
 Decide how many bytes to attempt to receive for the next UDP datagram.
static void jsocketpp::DatagramSocket::throwSizeMismatch (const std::size_t expected, const std::size_t actual, const bool isProbedKnown)
 Throw a descriptive exception when a UDP datagram’s size differs from what was expected.
void jsocketpp::DatagramSocket::enforceSendCapConnected (const std::size_t payloadSize) const
 Enforce UDP payload size limits for connected datagram sends.
void jsocketpp::DatagramSocket::sendUnconnectedTo (std::string_view host, Port port, const void *data, std::size_t len)
 Resolve and send one unconnected UDP datagram to the first compatible destination.
static std::span< const std::byte > jsocketpp::DatagramSocket::asBytes (const std::string_view sv) noexcept
 View a textual buffer as raw bytes without copying.
template<typename T>
static std::array< std::byte, sizeof(T)> jsocketpp::DatagramSocket::encodeLengthPrefixBE (std::size_t n)
 Encode a length value into a fixed-size, big-endian (network-order) byte array.
template<typename T>
void jsocketpp::DatagramSocket::sendPrefixedConnected (const std::span< const std::byte > payload) const
 Build and send a length-prefixed UDP datagram to the connected peer (no pre-wait).
template<typename T>
void jsocketpp::DatagramSocket::sendPrefixedUnconnected (const std::string_view host, const Port port, const std::span< const std::byte > payload)
 Build and send a length-prefixed UDP datagram to (host, port) on the unconnected path.
void jsocketpp::DatagramSocket::cacheLocalEndpoint () noexcept
 Cache the actual local endpoint assigned by the OS.
bool jsocketpp::DatagramSocket::tryGetRemoteSockaddr (sockaddr_storage &out, socklen_t &outLen) const
 Retrieve the remote endpoint sockaddr for this socket, if available.
 jsocketpp::MulticastSocket::MulticastSocket (Port localPort, std::string_view localAddress, std::optional< std::size_t > recvBufferSize=std::nullopt, std::optional< std::size_t > sendBufferSize=std::nullopt, std::optional< std::size_t > internalBufferSize=std::nullopt, bool reuseAddress=true, int soRecvTimeoutMillis=-1, int soSendTimeoutMillis=-1, bool nonBlocking=false, bool dualStack=true, bool autoBind=true)
 Constructs a fully configurable multicast socket for receiving and sending datagrams.
void jsocketpp::MulticastSocket::joinGroup (const std::string &groupAddr, const std::string &iface)
 Join a multicast group on an optional interface (string-friendly).
void jsocketpp::MulticastSocket::leaveGroup (const std::string &groupAddr, const std::string &iface="")
 Leave a multicast group on an optional interface (string-friendly).
void jsocketpp::MulticastSocket::setMulticastInterface (const std::string &iface)
 Select the default outgoing interface for multicast transmissions.
std::string jsocketpp::MulticastSocket::getMulticastInterface () const
 Get the currently selected egress interface for multicast transmissions.
void jsocketpp::MulticastSocket::setTimeToLive (int ttl)
 Set the time-to-live (TTL) / hop limit for outgoing multicast packets.
void jsocketpp::MulticastSocket::setLoopbackMode (bool enable)
 Enable or disable multicast loopback for this socket.
static in_addr jsocketpp::MulticastSocket::resolveIPv4 (std::string_view host)
 Resolve a host string to an IPv4 address (in_addr, network byte order).
static in6_addr jsocketpp::MulticastSocket::resolveIPv6 (std::string_view host)
 Resolve a host string to an IPv6 address (in6_addr).

Detailed Description

Classes and functions for UDP datagram networking.

Enumeration Type Documentation

◆ DatagramReceiveMode

enum class jsocketpp::DatagramReceiveMode : std::uint8_t
strong

Receive-time sizing policy for UDP datagrams.

Controls how DatagramSocket::read(...) chooses the number of bytes to request from the OS for the next UDP datagram. This affects both the likelihood of truncation and the number of syscalls performed per receive.

General behavior

  • In all modes, exactly one datagram is consumed per call.
  • The OS may truncate the payload if the destination buffer is smaller than the datagram.
  • For DatagramPacket& variants, the resizeBuffer parameter still applies and determines whether the packet’s buffer may be grown/shrunk by the call (see individual modes).
  • For raw-buffer variants (e.g., readInto()), the buffer size is fixed by the caller; no resizing is possible, but truncation may occur.

Performance note

  • Modes that preflight the exact datagram size typically issue an extra syscall (e.g., FIONREAD or MSG_PEEK|MSG_TRUNC) before the actual receive. This improves sizing accuracy at a small cost in throughput.
pkt.resize(8192); // provision capacity
// Default (no preflight): fastest path; may truncate if a datagram > 8192 arrives
std::size_t n = sock.read(pkt, true, jsocketpp::DatagramReceiveMode::NoPreflight);
// Preflight: probe exact size and (if allowed) grow pkt before receiving to avoid truncation
// PreflightMax: probe size but never request more than current capacity (or provided length)
Represents a UDP datagram packet, encapsulating both payload and addressing information.
Definition DatagramPacket.hpp:48
void resize(const size_t newSize)
Resize the packet's internal buffer.
Definition DatagramPacket.hpp:112
@ PreflightSize
Probe the exact size of the next datagram and size the receive accordingly.
Definition DatagramSocket.hpp:97
@ NoPreflight
Do not probe the datagram size; call recvfrom() directly.
Definition DatagramSocket.hpp:78
@ PreflightMax
Probe the size of the next datagram but cap it at the current buffer length.
Definition DatagramSocket.hpp:113
Since
1.0
Enumerator
NoPreflight 

Do not probe the datagram size; call recvfrom() directly.

  • Syscalls: 1 (fast path).
  • Resizing: If resizeBuffer == true, the packet may be shrunk after the receive to match the actual byte count; it is not grown beforehand.
  • Truncation: If the incoming datagram exceeds the current buffer size, the OS returns only the first buffer.size() bytes and discards the rest (standard UDP behavior).

Use this for fixed-size protocols or hot paths where every syscall counts.

PreflightSize 

Probe the exact size of the next datagram and size the receive accordingly.

  • Syscalls: up to 2 (probe, then receive).
  • Resizing (DatagramPacket): If resizeBuffer == true and the probed size is greater than packet.size(), the implementation may grow the packet (clamped to MaxDatagramPayloadSafe) to avoid truncation. If resizeBuffer == false, the packet is not grown and truncation may still occur.
  • Raw buffer: Reads exactly the probed size if it fits in len, otherwise truncates to len.
  • Accuracy: Uses platform facilities such as FIONREAD or a POSIX MSG_PEEK|MSG_TRUNC probe via nextDatagramSize(). On platforms where the probe is unavailable or unreliable, behavior gracefully degrades to NoPreflight.

Choose this when datagram sizes vary widely and avoiding truncation is more important than minimizing syscalls.

PreflightMax 

Probe the size of the next datagram but cap it at the current buffer length.

  • Syscalls: up to 2 (probe, then receive).
  • Resizing (DatagramPacket): If resizeBuffer == true and the probed size is less than or equal to packet.size(), the packet may be shrunk to the exact size after the receive. If the probed size is greater than packet.size(), truncation occurs; the packet is never grown.
  • Raw buffer: Reads exactly min(probedSize, len).
  • Accuracy: Same probe mechanism as PreflightSize.

Use this to avoid oversizing reads while still skipping unnecessary extra bytes for smaller datagrams.

◆ Direction

enum class jsocketpp::Direction : std::uint8_t
strong

I/O readiness selector used by waitReady().

Specifies which readiness condition to wait for on a datagram socket when calling waitReady(). On POSIX systems this corresponds to polling for POLLIN (readable) and/or POLLOUT (writable). On Windows, it maps to POLLRDNORM and/or POLLWRNORM via WSAPoll. For UDP sockets:

  • Read means at least one complete datagram is queued and can be received without blocking.
  • Write generally indicates the socket is writable (datagrams can be sent without blocking), though UDP sockets are often immediately writable unless the send buffer is full or an error is pending.
  • ReadWrite requests readiness for either read or write (logical OR of the above conditions).
Note
This selector controls which condition is awaited; timeout behavior and error reporting are defined by waitReady() itself. Exceptional poll conditions (e.g., error flags) are surfaced by waitReady() as exceptions.
See also
waitReady()
Enumerator
Read 

Wait until the socket is readable (one or more datagrams available).

Write 

Wait until the socket is writable (can send a datagram without blocking).

ReadWrite 

Wait until the socket is readable or writable (logical OR).

Function Documentation

◆ asBytes()

std::span< const std::byte > jsocketpp::DatagramSocket::asBytes ( const std::string_view sv)
inlinestaticprotectednoexcept

View a textual buffer as raw bytes without copying.

Returns a std::span<const std::byte> that references the same memory as the input std::string_view sv. This is an O(1), zero-allocation conversion intended for APIs that operate on binary payloads (e.g., UDP datagram sends) while callers may naturally hold data as text.

  • The resulting span does not include any null terminator; it covers exactly sv.size() bytes starting at sv.data().
  • The span is non-owning; its lifetime and validity are tied to the lifetime of the storage viewed by sv. Callers must ensure that storage remains alive until any I/O using the span completes.
  • Aliasing/strict-aliasing: viewing char/unsigned char storage as std::byte for read-only purposes is well-formed; this helper never writes through the span.
Parameters
[in]svThe textual data to re-interpret as bytes. May be empty.
Returns
A byte-span referencing the same memory as sv (possibly empty).
Note
This function performs no validation or transcoding; it is a shallow view conversion only. For structured data, prefer explicit serialization.
Since
1.0
See also
write(std::span<const std::byte>), write(std::string_view), writePrefixed<T>(std::string_view), writePrefixed<T>(std::span<const std::byte>), sendPrefixedConnected<T>(std::span<const std::byte>), sendPrefixedUnconnected<T>(std::string_view, Port, std::span<const std::byte>)
// Treat a string payload as raw bytes for binary-oriented send paths:
std::string payload = "hello";
auto bytes = DatagramSocket::asBytes(std::string_view{payload});
sock.write(bytes); // sends as a single UDP datagram
static std::span< const std::byte > asBytes(const std::string_view sv) noexcept
View a textual buffer as raw bytes without copying.
Definition DatagramSocket.hpp:4544

◆ bind() [1/3]

void DatagramSocket::bind ( )

Binds the datagram socket to all available interfaces on an ephemeral port.

This method binds the DatagramSocket to an ephemeral (auto-assigned) local port on all local network interfaces (0.0.0.0 for IPv4 or :: for IPv6), depending on system configuration and address resolution.

Common Use Cases

  • UDP client sockets that do not require a specific local port
  • Transient sockets used for fire-and-forget messages, RPC, or NAT traversal
  • Applications that allow the OS to choose a source port dynamically

Behavior

  • Uses getaddrinfo() with AI_PASSIVE and a wildcard local address (0.0.0.0 or ::)
  • Binds to the first successfully resolved and compatible local address
  • On success, updates internal _isBound flag and enables receiving datagrams
Note
This method may only be called once per socket instance. Rebinding is not supported.
If the socket was constructed with an already-resolved address, this will override it.
Exceptions
SocketExceptionif address resolution or binding fails.
sock.bind(); // Binds to all interfaces on an ephemeral port (e.g., 0.0.0.0:49512 or [::]:49512)
DatagramSocket(Port localPort=0, std::string_view localAddress="", std::optional< std::size_t > recvBufferSize=std::nullopt, std::optional< std::size_t > sendBufferSize=std::nullopt, std::optional< std::size_t > internalBufferSize=std::nullopt, bool reuseAddress=true, int soRecvTimeoutMillis=-1, int soSendTimeoutMillis=-1, bool nonBlocking=false, bool dualStack=true, bool autoBind=true, bool autoConnect=false, std::string_view remoteAddress="", Port remotePort=0, int connectTimeoutMillis=-1)
Creates a UDP socket, optionally binds to a local address, and optionally connects to a remote peer.
Definition DatagramSocket.cpp:12
void bind()
Binds the datagram socket to all available interfaces on an ephemeral port.
Definition DatagramSocket.cpp:243
See also
bind(Port localPort), bind(std::string_view localAddress, Port localPort), getLocalSocketAddress()

◆ bind() [2/3]

void DatagramSocket::bind ( Port localPort)

Binds the datagram socket to a specific local port on all network interfaces.

This overload binds the socket to the given UDP localPort across all available network interfaces, using a wildcard address (0.0.0.0 for IPv4 or :: for IPv6).

Common Use Cases

  • Server-side sockets that need to receive packets on a known port
  • P2P or NAT traversal clients using fixed source ports
  • Test setups or replay systems where the port number must be predictable

Behavior

  • Uses getaddrinfo() with AI_PASSIVE and a null host to resolve wildcard binding addresses
  • Attempts all resolved addresses until bind() succeeds
  • If successful, sets _isBound = true and enables subsequent read() or recvFrom() operations
Parameters
[in]localPortUDP port number to bind to. Must be in the range [1, 65535], or 0 to request an ephemeral port.
Note
This method may only be called once per socket instance. Rebinding is not supported.
If the specified port is already in use, a SocketException will be thrown.
Exceptions
SocketExceptionif address resolution or binding fails, or if the socket is already bound.
server.bind(12345); // Bind to port 12345 on all interfaces
See also
bind(), bind(std::string_view, Port), getLocalSocketAddress(), setReuseAddress()

◆ bind() [3/3]

void DatagramSocket::bind ( std::string_view localAddress,
Port localPort )

Binds the datagram socket to a specific local IP address and port.

This method allows full control over the local binding interface by specifying both the local IP address (host) and port. It supports IPv4 and IPv6 addresses, including loopback, multicast-capable interfaces, and link-local addresses.

Common Use Cases

  • Multihomed systems binding to a specific NIC/interface
  • Clients or servers requiring fixed local IP-port pairing
  • Binding to loopback or link-local addresses
  • Low-level networking tools (e.g., packet sniffers, trace clients)

Behavior

  • Uses getaddrinfo() to resolve the provided IP/hostname and port
  • Tries all resolved addresses until one binds successfully
  • Updates internal state to reflect the binding result
Parameters
[in]localAddressLocal IP address or hostname to bind to (e.g., "127.0.0.1", "::1", "eth0.local"). Use "0.0.0.0" or "::" to bind to all interfaces (same as bind(port)).
[in]localPortLocal UDP port number to bind to. Use 0 for ephemeral port assignment.
Note
This method may only be called once. Rebinding is not supported.
If resolution fails, or no address can be bound, a SocketException is thrown.
Exceptions
SocketExceptionif address resolution or binding fails.
sock.bind("192.168.1.42", 9000); // Bind to specific interface and port
See also
bind(), bind(Port), getLocalSocketAddress(), setReuseAddress()

◆ cacheLocalEndpoint()

void jsocketpp::DatagramSocket::cacheLocalEndpoint ( )
inlineprotectednoexcept

Cache the actual local endpoint assigned by the OS.

Invokes getsockname() on the socket and stores the result in _localAddr/_localAddrLen, setting _haveLocalAddr to true on success. Call this immediately after a successful bind() or after a UDP connect() that implicitly binds an ephemeral port. If getsockname() fails, the existing cached values are left unchanged.

Postcondition
On success: _haveLocalAddr == true and _localAddr/_localAddrLen contain a valid AF_INET or AF_INET6 endpoint. On failure: cache remains as it was.

@thread_safety Intended for the owning thread of the socket. Not synchronized against concurrent close(); coordinate externally if those may race.

Exceptions
None.This function is noexcept and never throws.

◆ chooseReceiveSize()

std::size_t jsocketpp::DatagramSocket::chooseReceiveSize ( ) const
inlineprotected

Decide how many bytes to attempt to receive for the next UDP datagram.

This method centralizes the library’s Java-like sizing policy so all UDP read() variants behave consistently while keeping _internalBuffer as reusable storage only (never resized here).

Policy order:

  1. Prefer exact size from jsocketpp::internal::nextDatagramSize(getSocketFd()). If the platform reports the pending datagram length, use that value.
  2. Otherwise, use caller capacity: if _internalBuffer.size() > 0, treat it as the caller-provided maximum (Java semantics).
  3. If the internal buffer is unset/empty, fall back to DefaultDatagramReceiveSize.
  4. Clamp the chosen value to MaxDatagramPayloadSafe (65,507 bytes) to avoid oversizing.

Semantics:

  • This method performs no I/O and never resizes _internalBuffer.
  • The returned value is a target receive size; the actual bytes read may be less (e.g., zero-length datagrams, short reads, or errors).
Returns
Proposed byte count to pass to recv() / recvfrom() for the next datagram.
Precondition
getSocketFd() is valid if the result will be used immediately for I/O.
Note
If the OS cannot report exact size and the sender’s datagram exceeds both the chosen value and available destination storage, the payload may be truncated (standard UDP behavior).
See also
jsocketpp::internal::nextDatagramSize()
DefaultDatagramReceiveSize
MaxDatagramPayloadSafe
Since
1.0

◆ cleanup()

void DatagramSocket::cleanup ( )
protected

Internal helper that releases socket resources and resets all internal state.

This method safely resets the DatagramSocket to an uninitialized state. It is used during error recovery to release partially constructed socket state, and ensures the object no longer appears bound or connected after failure.


⚙️ Behavior


🔒 Safety

Note
This method is private and should not be exposed to users directly. It is designed for internal lifecycle management and exception-safe cleanup.
See also
cleanupAndThrow(), cleanupAndRethrow(), CloseSocket()

◆ cleanupAndRethrow()

void DatagramSocket::cleanupAndRethrow ( )
protected

Cleans up the datagram socket and rethrows the currently active exception.

This method is intended to be used inside a catch block when an exception occurs during socket construction or setup. It ensures all internal resources are safely released before rethrowing the original exception, leaving the socket in an uninitialized and safe state.


⚙️ Behavior

Internally calls cleanup(), which:

  • Closes the socket if it is open
  • Sets the socket descriptor to INVALID_SOCKET
  • Resets connection state flags:
  • Clears cached local/remote address structures

Then rethrows the active exception using throw;.


⚠️ Usage Notes

  • Must be invoked only from within a valid catch block
  • If no exception is currently being handled, calling this method causes undefined behavior
  • Never accepts an exception object — throw; preserves full type and context

🧠 Example

try {
} catch (...) {
cleanupAndRethrow(); // Fully resets state and rethrows original exception
}
void setSoRecvTimeout(int millis)
Sets the socket receive timeout (SO_RCVTIMEO) in milliseconds.
Definition SocketOptions.cpp:160
void setNonBlocking(bool nonBlocking)
Enables or disables non-blocking mode on the socket.
Definition SocketOptions.cpp:223
void cleanupAndRethrow()
Cleans up the datagram socket and rethrows the currently active exception.
Definition DatagramSocket.cpp:176
Exceptions
SocketExceptionor the original active exception
See also
cleanup(), cleanupAndThrow()
SocketException

◆ cleanupAndThrow()

void DatagramSocket::cleanupAndThrow ( int errorCode)
protected

Releases all socket resources and throws a SocketException with the given error code.

This method performs complete internal cleanup of the datagram socket and then throws a SocketException. It is typically invoked when construction, binding, or configuration of the socket fails, ensuring the object is left in a safe, uninitialized state.


⚙️ Behavior

Internally delegates to cleanup(), which:

  • Closes the socket if open
  • Resets the socket descriptor to INVALID_SOCKET
  • Resets internal state flags:
  • Clears cached local/remote address structures

After cleanup, throws a SocketException with:

  • The provided errorCode
  • A descriptive message from SocketErrorMessage(errorCode)

🧠 Example

{
}
SOCKET getSocketFd() const noexcept
Retrieves the native socket handle (file descriptor or OS-level handle).
Definition SocketOptions.hpp:275
void cleanupAndThrow(int errorCode)
Releases all socket resources and throws a SocketException with the given error code.
Definition DatagramSocket.cpp:170
int GetSocketError()
Definition common.hpp:246
constexpr SOCKET SOCKET_ERROR
Definition common.hpp:265
Parameters
[in]errorCodeThe system or application-level error code to report.
Exceptions
SocketExceptionAlways throws after cleanup.
See also
cleanup()
cleanupAndRethrow()
SocketException, SocketErrorMessage()

◆ close()

void DatagramSocket::close ( )

Closes the datagram socket and releases its underlying system resources.

This method performs a full teardown of the datagram socket, closing the underlying file descriptor/handle and releasing all associated resources. After closure, the socket becomes invalid and cannot be reused.


⚙️ Core Behavior

  • Invalidates the socket descriptor (_sockFd = INVALID_SOCKET)
  • Releases system-level socket resources via ::close() or ::closesocket()
  • Resets all internal state flags (_isBound, _isConnected)
  • Clears address resolution data and remote peer information
  • Makes the socket unsuitable for further I/O operations

🔒 Safety

  • Safe to call multiple times (idempotent)
  • Thread-safe with respect to other instances
  • Ensures no resource leaks even after errors
  • Preserves exception safety guarantees

🧪 Example

sock.bind(12345);
// ... use socket ...
sock.close(); // Release all resources
assert(sock.isClosed());
void close()
Closes the datagram socket and releases its underlying system resources.
Definition DatagramSocket.cpp:196
bool isClosed() const noexcept
Checks whether the datagram socket has been closed or is otherwise invalid.
Definition DatagramSocket.hpp:3988
Exceptions
SocketExceptionIf the underlying close operation fails unexpectedly.
Note
  • Any pending operations on the socket will be aborted
  • Subsequent operations will throw SocketException
  • Use isClosed() to check socket state
See also
isClosed() To verify socket state
isValid() Alternative check for usability
cleanup() Internal cleanup helper
Since
1.0

◆ connect()

void DatagramSocket::connect ( std::string_view host,
Port port,
int timeoutMillis )

Connect this UDP socket to a default peer (set the default destination).

Establishes a default remote endpoint for the datagram socket. After a successful call, send/receive operations that use the connected variants (e.g., send, recv) no longer require an explicit destination address. Unlike TCP, UDP "connect" performs no handshake; it simply sets the default peer and may implicitly bind the local endpoint (address/port).

This implementation:

  • Resolves host + port to a linked list of address candidates (IPv6 and/or IPv4).
  • Iterates all candidates in order until one succeeds.
  • If timeoutMillis ≥ 0, temporarily switches the socket to non-blocking mode and uses select() to wait for writability, respecting a single overall timeout budget across all candidates (not per-candidate).
  • On success, caches the local endpoint (via getsockname()), sets _isBound = true (if it wasn’t already), and marks the socket as connected.
Parameters
[in]hostRemote hostname or IP literal (IPv4/IPv6).
[in]portRemote UDP port.
[in]timeoutMillisConnection timeout in milliseconds. If < 0, the call is blocking. If 0, the function attempts a non-blocking connect and will time out immediately unless completion is instantaneous.
Precondition
The socket must be open and not already connected.
Postcondition
On success:
  • The socket has a default peer set (connected UDP).
  • The local endpoint cache is populated to reflect any implicit bind.
  • _isConnected == true and _isBound == true (if an implicit bind occurred).
Exceptions
SocketException
  • If called when already connected.
  • If name resolution yields no candidates.
  • If a candidate fails synchronously (and other candidates also fail), or if select()/getsockopt(SO_ERROR) reports an error. The exception carries GetSocketError() and SocketErrorMessage(GetSocketError()).
SocketTimeoutException
  • If the connection does not complete within timeoutMillis across all candidates (including the case timeoutMillis == 0 and the operation cannot complete immediately).
Notes
  • The total elapsed time across candidate attempts will not exceed timeoutMillis.
  • On Windows and POSIX, writability after select() is not a guarantee of success; this method checks SO_ERROR to confirm or retrieve the per-candidate failure code.
  • If you routinely connect with timeouts, consider replacing select() with a poll()-based wait to avoid FD_SETSIZE constraints.
Warning
When timeoutMillis ≥ 0 and getSocketFd() >= FD_SETSIZE, select() cannot be used and this function throws a SocketException before attempting the connection.
Note
Thread-safety: intended for the socket’s owning thread. Do not call concurrently with close() or other operations that mutate connection state.
s.open(AF_UNSPEC); // create socket
s.connect("example.net", 5353, 2000); // iterate v6/v4 candidates, 2s overall timeout
s.send(data, len); // now uses the default peer
void connect(std::string_view host, Port port, int timeoutMillis)
Connect this UDP socket to a default peer (set the default destination).
Definition DatagramSocket.cpp:249

◆ DatagramSocket() [1/3]

jsocketpp::DatagramSocket::DatagramSocket ( const DatagramSocket & )
delete

Copy constructor (deleted) for DatagramSocket.

The copy constructor is explicitly deleted to prevent copying of DatagramSocket instances. This class wraps a native socket file descriptor (SOCKET) and manages system-level resources that cannot be safely or meaningfully duplicated.

Copying would result in multiple objects referring to the same underlying socket, which would violate ownership semantics and could lead to:

  • Double closure of the same socket
  • Undefined behavior in concurrent scenarios
  • Silent data corruption if two sockets share internal buffers

Instead, use move semantics to transfer ownership safely between instances.

Note
All socket classes in the library are non-copyable by design to preserve RAII guarantees and strict resource control.
DatagramSocket a(12345);
DatagramSocket b = a; // ❌ Compilation error (copy constructor is deleted)
See also
DatagramSocket(DatagramSocket&&) noexcept

◆ DatagramSocket() [2/3]

jsocketpp::DatagramSocket::DatagramSocket ( DatagramSocket && rhs)
inlinenoexcept

Move constructor for DatagramSocket.

Transfers ownership of the underlying socket file descriptor and internal state from another DatagramSocket instance. After the move, the source object is left in a valid but unspecified state and should not be used.

What Is Transferred

  • Native socket handle (_sockFd)
  • Address resolution pointers (_addrInfoPtr, _selectedAddrInfo)
  • Local address metadata
  • Internal receive buffer
  • Port number

Rationale

  • Enables safe transfer of socket ownership
  • Preserves resource integrity without duplicating system handles
  • Supports RAII and container use (e.g., std::vector<DatagramSocket>)
Note
The moved-from object is invalidated and cannot be reused.
DatagramSocket a(12345);
DatagramSocket b = std::move(a); // ✅ b now owns the socket
See also
operator=(DatagramSocket&&) noexcept

◆ DatagramSocket() [3/3]

DatagramSocket::DatagramSocket ( Port localPort = 0,
std::string_view localAddress = "",
std::optional< std::size_t > recvBufferSize = std::nullopt,
std::optional< std::size_t > sendBufferSize = std::nullopt,
std::optional< std::size_t > internalBufferSize = std::nullopt,
bool reuseAddress = true,
int soRecvTimeoutMillis = -1,
int soSendTimeoutMillis = -1,
bool nonBlocking = false,
bool dualStack = true,
bool autoBind = true,
bool autoConnect = false,
std::string_view remoteAddress = "",
Port remotePort = 0,
int connectTimeoutMillis = -1 )
explicit

Creates a UDP socket, optionally binds to a local address, and optionally connects to a remote peer.

This constructor supports both server-style and client-style UDP sockets:

  • Server mode: Binds to a local address and receives datagrams from any source
  • Client mode: Optionally connects to a remote peer, enabling send()/recv() and automatic ICMP error handling

The socket supports:

  • IPv4 and IPv6 (with optional dual-stack fallback)
  • Local binding (bind()), optionally done during construction
  • Connection to a remote host/port using ::connect() semantics
  • OS-level socket configuration (SO_RCVBUF, SO_SNDBUF, timeouts, etc.)
  • Optional non-blocking mode

Usage Modes

  • Bound UDP Server Useful for listening on a specific port/interface for datagrams from any peer.

    DatagramSocket s(53, "0.0.0.0", ..., true, false); // bind only
  • Connected UDP Client Binds (optional) and then connects to a fixed remote peer. Enables write() / read(), ICMP error propagation, and performance improvements.

    DatagramSocket s(0, "", ..., true, true, "1.2.3.4", 9000, 3000); // bind and connect with timeout

Configuration Parameters

Parameters
[in]localPortThe local port to bind from. Use 0 for ephemeral.
[in]localAddressThe local IP to bind from (e.g., "192.168.1.100" or "::"). Empty for wildcard.
[in]recvBufferSizeOptional socket receive buffer size (SO_RCVBUF)
[in]sendBufferSizeOptional socket send buffer size (SO_SNDBUF)
[in]internalBufferSizeOptional internal buffer size used by high-level read methods
[in]reuseAddressIf true, enables SO_REUSEADDR to allow rebinding the port
[in]soRecvTimeoutMillisTimeout for receive operations in milliseconds (-1 disables)
[in]soSendTimeoutMillisTimeout for send operations in milliseconds (-1 disables)
[in]nonBlockingIf true, sets the socket to non-blocking mode immediately
[in]dualStackIf true, enables IPv6 sockets to accept IPv4-mapped addresses
[in]autoBindIf true, performs a bind() using localAddress and localPort after construction
[in]autoConnectIf true, immediately connects to the remote peer using remoteAddress and remotePort
[in]remoteAddressThe remote host/IP to connect to (used only if autoConnect == true)
[in]remotePortThe remote UDP port to connect to (used only if autoConnect == true)
[in]connectTimeoutMillisTimeout (in ms) for the connection attempt when autoConnect == true:
  • < 0 performs a traditional blocking connect()
  • >= 0 uses a timeout-aware non-blocking connect

Throws

Exceptions
SocketExceptionIf any step of socket resolution, creation, binding, configuration, or connection fails
SocketTimeoutExceptionIf the connect() call exceeds the specified connectTimeoutMillis timeout

See also
bind(), connect(), setSoRecvTimeout(), setSoSendTimeout(), isConnected(), write(), writeTo()

◆ discard()

void DatagramSocket::discard ( const DatagramReadOptions & opts = {}) const

Discard the next UDP datagram without copying it out.

Since
1.0

Consumes exactly one datagram from the socket and discards its bytes. This method ignores the datagram size and never throws due to truncation. Timeouts and OS-level receive errors still apply. On unconnected sockets, when opts.updateLastRemote is true, the internally tracked “last remote” endpoint is updated to the sender of the discarded datagram.

Parameters
[in]optsRead options controlling sender bookkeeping and receive flags. The mode field is ignored (a single receive is always performed). Truncation reporting is ignored.
Exceptions
SocketExceptionIf the socket is not open or an OS-level receive error occurs (message via SocketErrorMessage).
SocketTimeoutExceptionIf a configured receive timeout elapses before any datagram is available, or when the socket is non-blocking and no data is available (would-block).
Precondition
The socket has been successfully created/opened.
Postcondition
Exactly one datagram has been removed from the socket’s receive queue. For unconnected sockets, when opts.updateLastRemote is true, the internal “last remote” reflects that sender.
Example
// Drop the next datagram, whatever its size
sock.discard();

◆ discardExact()

void DatagramSocket::discardExact ( std::size_t n,
const DatagramReadOptions & opts = {} ) const

Discard the next UDP datagram only if its payload size is exactly n bytes.

Since
1.0

Enforces exact-length semantics while draining the datagram:

  • If a reliable size probe is available, the method verifies the next datagram size equals n and throws before reading when it does not, so the datagram remains queued.
  • If size cannot be probed, it performs exactly one receive of up to n bytes. If the datagram is larger than n, the kernel truncates it; this method then throws. If the datagram is smaller than n, it also throws. In other words, the datagram must be exactly n bytes or the call fails.

The discard operation minimizes copying: when the size is known to be n, the method reads with a tiny scratch buffer to consume the datagram (the kernel drops the remainder).

On unconnected sockets, when opts.updateLastRemote is true, the internally tracked “last remote” endpoint is updated to the sender of the discarded datagram.

Parameters
[in]nRequired datagram payload size (> 0).
[in]optsRead options controlling sender bookkeeping and receive flags. Truncation policy in opts is ignored; this method enforces its own exact-length checks.
Exceptions
SocketExceptionIf the socket is not open; n == 0; OS-level receive errors occur (message via SocketErrorMessage); or the next datagram’s size is not exactly n bytes.
SocketTimeoutExceptionIf a configured receive timeout elapses before any datagram is available, or when the socket is non-blocking and no data is available (would-block).
Precondition
The socket has been successfully created/opened. n > 0.
Postcondition
Exactly one datagram has been removed from the socket’s receive queue if and only if its size was n. For unconnected sockets, when opts.updateLastRemote is true, the internal “last remote” reflects that sender.
Example
// Drop the next datagram only if it is exactly 512 bytes
sock.discardExact(512);

◆ disconnect()

void DatagramSocket::disconnect ( )

Disconnect this UDP socket from its current default peer.

Dissolves the association set by a prior connect() without closing the socket. Internally, this issues ::connect(fd, { .sa_family = AF_UNSPEC }, sizeof(sockaddr)), which is the standard UDP “disconnect” idiom on POSIX and Winsock. The socket remains open and (if previously bound) stays bound to its local address/port; only the default remote peer is cleared.

This implementation:

  • Treats a not-currently-connected socket as a no-op.
  • Throws if the socket handle is invalid or if the kernel connect(AF_UNSPEC) call fails.
  • Preserves the cached local endpoint and _isBound state.
  • Clears any cached remote endpoint (_haveRemoteAddr = false, zeroes _remoteAddr, and _remoteAddrLen = 0).
Precondition
The socket must be open. If _isConnected == false, the call is a no-op.
Postcondition
_isConnected == false. Local bind (if any) and its cache remain intact. Remote-endpoint cache is cleared.
Exceptions
SocketExceptionIf the socket is not open, or if the underlying connect(AF_UNSPEC) fails. The exception carries GetSocketError() and SocketErrorMessage(GetSocketError()).
Note
Thread-safety: intended for the socket’s owning thread. Do not call concurrently with close() or other operations that mutate connection state.
POSIX: the call may be retried internally if interrupted by a signal (EINTR).
s.connect("203.0.113.5", 9999, 1000);
// ... use connected send/recv ...
s.disconnect(); // clears default peer; socket remains open and bound
void disconnect()
Disconnect this UDP socket from its current default peer.
Definition DatagramSocket.cpp:419

◆ encodeLengthPrefixBE()

template<typename T>
std::array< std::byte, sizeof(T)> jsocketpp::DatagramSocket::encodeLengthPrefixBE ( std::size_t n)
inlinestaticprotected

Encode a length value into a fixed-size, big-endian (network-order) byte array.

Template Parameters
TUnsigned integral type used for the length prefix. Typical choices are std::uint8_t, std::uint16_t, std::uint32_t, or std::uint64_t. A compile-time check enforces that T is an unsigned integral.

Converts n into its big-endian (network byte order) representation using exactly sizeof(T) bytes and returns the result as std::array<std::byte, sizeof(T)>. The function is O(sizeof(T)) and allocation-free.

  • When sizeof(T) == 1, the result is a single byte: n & 0xFF.
  • For larger T, the most significant byte appears first in the array.
  • Only the low sizeof(T) * 8 bits of n are representable; values that do not fit are rejected with a logical exception (see Throws).

This helper is intended for building length-prefixed UDP frames with a prefix followed by payload bytes, where the prefix must be in network byte order for interoperability.

Parameters
[in]nThe length value to encode. Must satisfy n <= std::numeric_limits<T>::max().
Returns
A std::array<std::byte, sizeof(T)> containing n encoded in big-endian order.
Exceptions
SocketException
  • Logical (error code = 0): if n exceeds std::numeric_limits<T>::max().
Since
1.0
See also
writePrefixed<T>(std::string_view), writePrefixed<T>(std::span<const std::byte>), writePrefixedTo<T>(std::string_view, Port, std::string_view), writePrefixedTo<T>(std::string_view, Port, std::span<const std::byte>)
// Example: encode a 16-bit length (42) as network-order bytes { 0x00, 0x2A }.
assert(static_cast<unsigned>(be[0]) == 0x00);
assert(static_cast<unsigned>(be[1]) == 0x2A);
static std::array< std::byte, sizeof(T)> encodeLengthPrefixBE(std::size_t n)
Encode a length value into a fixed-size, big-endian (network-order) byte array.
Definition DatagramSocket.hpp:4592

◆ enforceSendCapConnected()

void jsocketpp::DatagramSocket::enforceSendCapConnected ( const std::size_t payloadSize) const
inlineprotected

Enforce UDP payload size limits for connected datagram sends.

Validates that a single datagram of payloadSize bytes can be sent to the currently connected peer without exceeding protocol-level maxima.

The check is conservative by default:

  • Always allows up to MaxDatagramPayloadSafe (65,507 bytes), which is safe on both IPv4 and IPv6.
  • If the connected peer is IPv6 (AF_INET6), allows the IPv6 theoretical maximum (MaxUdpPayloadIPv6 = 65,527) while continuing to reject anything larger.

If the socket is connected to IPv4 (AF_INET) and payloadSize exceeds the IPv4 limit (MaxUdpPayloadIPv4 = 65,507), an exception is thrown before calling send(), providing a precise, user-friendly error message.

The remote address family is determined via: 1) cached last-peer address when available, otherwise 2) a getpeername() query on the connected socket.


Rationale

Proactive validation yields deterministic, actionable errors (instead of a vague EMSGSIZE from the kernel) and avoids futile syscalls.


Example (internal use)

// Inside write(std::string_view):
internal::sendExact(getSocketFd(), value.data(), value.size());
void sendExact(SOCKET fd, const void *data, std::size_t size)
Sends an entire datagram to a connected peer using send().
Definition common.cpp:477
void enforceSendCapConnected(const std::size_t payloadSize) const
Enforce UDP payload size limits for connected datagram sends.
Definition DatagramSocket.hpp:4407

Parameters
[in]payloadSizeNumber of bytes intended for a single datagram.
Precondition
getSocketFd() != INVALID_SOCKET
isConnected() == true
Exceptions
SocketException
  • If the socket is not open or not connected (logical error).
  • If getpeername() fails while determining the connected peer family (OS error; uses GetSocketError()/SocketErrorMessage()).
  • If payloadSize exceeds the permitted maximum for the connected peer’s family.
Note
This method does not enforce path-MTU/non-fragmenting policies; it only enforces absolute protocol maxima to prevent guaranteed failures.
See also
MaxDatagramPayloadSafe, MaxUdpPayloadIPv4, MaxUdpPayloadIPv6, write(), writeTo()

◆ getLastPeerSockAddr()

std::optional< std::pair< sockaddr_storage, socklen_t > > jsocketpp::DatagramSocket::getLastPeerSockAddr ( ) const
inlinenodiscard

Retrieves the raw socket address of the last known remote peer.

This method exposes the internal low-level sockaddr_storage structure representing the last known remote peer that this socket communicated with. It is useful in advanced use cases where direct access to address structures is required — for example:

  • Custom routing or connection tracking
  • Creating new sockets targeting the same peer
  • Implementing security checks or access controls
  • Avoiding repeated DNS resolution

🔁 Behavior Based on Mode

  • Connected Socket:
    • Reflects the peer specified via connect().
    • Remains constant until the socket is closed or reset.
  • Unconnected Socket:
    • Reflects the peer involved in the most recent:
    • If no such operation has occurred, the result is empty.

Example

auto remote = sock.getLastPeerSockAddr();
if (remote) {
const sockaddr* sa = reinterpret_cast<const sockaddr*>(&remote->first);
// Now you can use sendto(), bind(), connect(), etc.
}

Returns
  • std::optional<std::pair<sockaddr_storage, socklen_t>>:
    • .first contains the raw peer address
    • .second is the valid length of the address
  • Returns std::nullopt if the socket has not communicated with any peer.
Note
This is a low-level method. Use getRemoteIp() or getRemoteSocketAddress() for string-formatted access.
The returned structure is a copy; modifying it has no effect on socket state.
See also
getRemoteIp(), getRemotePort(), writeTo(), read(), isConnected(), connect()

◆ getLocalIp()

std::string DatagramSocket::getLocalIp ( bool convertIPv4Mapped)
nodiscard

Return the local interface IP address for this UDP socket.

Returns the textual IP address (IPv4 or IPv6) currently bound to this socket. If a cached local endpoint is available, it is used without a syscall. Otherwise, this method performs a single getsockname() and, on success, updates the internal cache (only if the kernel reports a non-zero port, i.e., the socket is actually bound). This method is non-const because it may refresh and persist the cached local endpoint.

When convertIPv4Mapped is true and the underlying address is an IPv6 IPv4-mapped address (::ffff:a.b.c.d), the returned string is converted to an IPv4 literal (a.b.c.d). For IPv6 link-local addresses, the scope ID may be included if available (e.g., fe80::1eth0), depending on platform conventions and the socket's bound interface.

Parameters
[in]convertIPv4MappedIf true, convert IPv4-mapped IPv6 addresses to IPv4 text form; if false, return the canonical address text as reported by the OS.
Returns
std::string The local IP address in presentation form.
Precondition
isOpen() == true.
Postcondition
If the socket is bound to a non-zero port, the internal local-endpoint cache is updated and marked valid.
Exceptions
SocketException
  • If the socket is not open.
  • If getsockname() fails; the exception carries GetSocketError() and SocketErrorMessage(GetSocketError()).
Note
Complexity: O(1) on a warm cache; otherwise one getsockname() call.
Thread-safety: intended for the socket's owning thread. Do not call concurrently with close() or other operations that tear down the descriptor.
s.bind("0.0.0.0", 0); // OS assigns an address/port
auto ip = s.getLocalIp(true); // e.g., "192.0.2.10"
std::string getLocalIp(bool convertIPv4Mapped)
Return the local interface IP address for this UDP socket.
Definition DatagramSocket.cpp:1651

◆ getLocalPort()

Port DatagramSocket::getLocalPort ( )
nodiscard

Return the local UDP port this socket is bound to.

Returns the numeric port currently bound to this socket. If a cached local endpoint is available, it is used without a syscall. Otherwise, this method performs a single getsockname() and, on success, updates the internal cache only if the kernel reports a non-zero port (i.e., the socket is actually bound). This method is non-const because it may refresh and persist the cached local endpoint.

Returns
Port The local UDP port number.
Precondition
isOpen() == true.
Postcondition
If the socket is bound to a non-zero port, the internal local-endpoint cache is updated and marked valid.
Exceptions
SocketException
  • If the socket is not open.
  • If getsockname() fails; the exception carries GetSocketError() and SocketErrorMessage(GetSocketError()).
Note
Complexity: O(1) with a warm cache; otherwise one getsockname() call.
Thread-safety: intended for the socket’s owning thread. Do not call concurrently with close() or other teardown operations.
s.bind("::", 0); // OS selects an ephemeral port
Port p = s.getLocalPort(); // e.g., 54321
std::uint16_t Port
Type alias representing a TCP or UDP port number (1–65535).
Definition common.hpp:392
Port getLocalPort()
Return the local UDP port this socket is bound to.
Definition DatagramSocket.cpp:1681

◆ getLocalSocketAddress()

std::string DatagramSocket::getLocalSocketAddress ( bool convertIPv4Mapped)
nodiscard

Return the local endpoint as a single "ip:port" string.

Builds a presentation string for the socket’s current local endpoint by combining the local IP and port. If a cached local endpoint is available, it is used without a syscall. Otherwise, this method performs a single getsockname() and, on success, updates the internal cache only if the kernel reports a non-zero port (i.e., the socket is actually bound). This method is non-const because it may refresh and persist the cached local endpoint. For IPv6 addresses, the IP may be bracketed (e.g., [2001:db8::1]:54321) depending on the formatting used by the underlying helpers.

When convertIPv4Mapped is true and the underlying address is an IPv6 IPv4-mapped address (::ffff:a.b.c.d), the IP portion is converted to an IPv4 literal (a.b.c.d) before concatenation.

Parameters
[in]convertIPv4MappedIf true, convert IPv4-mapped IPv6 addresses to IPv4 text form in the result.
Returns
std::string The local endpoint string, e.g., "192.0.2.10:54321" or "[2001:db8::1]:54321".
Precondition
isOpen() == true.
Postcondition
If the socket is bound to a non-zero port, the internal local-endpoint cache is updated and marked valid.
Exceptions
SocketException
  • If the socket is not open.
  • If getsockname() fails; the exception carries GetSocketError() and SocketErrorMessage(GetSocketError()).
Note
Complexity: O(1) on a warm cache; otherwise one getsockname() call.
Thread-safety: intended for the socket’s owning thread. Do not call concurrently with close() or other teardown operations.
s.bind("0.0.0.0", 0); // OS assigns an address/port
auto ep = s.getLocalSocketAddress(true); // e.g., "192.0.2.10:54321"
std::string getLocalSocketAddress(bool convertIPv4Mapped)
Return the local endpoint as a single "ip:port" string.
Definition DatagramSocket.cpp:1708

◆ getMTU()

std::optional< int > DatagramSocket::getMTU ( ) const
nodiscard

Retrieves the Maximum Transmission Unit (MTU) of the local interface associated with the socket.

This method attempts to query the MTU of the network interface to which the socket is currently bound. It supports both Windows and POSIX platforms using appropriate system APIs and returns the result as an optional integer.


🔍 What is the MTU?

The MTU is the largest size (in bytes) of a datagram that can be sent over a network interface without fragmentation. For example, Ethernet IPv4 commonly uses an MTU of 1500 bytes, while the payload limit for UDP is typically 1472 bytes after IP/UDP headers.


⚙️ Platform Behavior

  • Windows:
    • Uses GetAdaptersAddresses() to enumerate system interfaces.
    • Uses getsockname() to determine the bound local IP.
    • Compares adapter unicast IPs to the bound address using normalized logic that handles IPv4 and IPv4-mapped IPv6.
    • Returns the MTU for the matched adapter.
  • POSIX (Linux, macOS, etc.):
    • Uses getsockname() to retrieve the bound IP.
    • Uses getifaddrs() to map the IP to a named interface.
    • Uses ioctl(SIOCGIFMTU) to retrieve the MTU for the interface.

✅ Use Cases

  • Enforce maximum UDP payload size to avoid fragmentation
  • Tune protocol chunk sizes dynamically based on interface limits
  • Avoid silent datagram drops on MTU-exceeding payloads

Returns
  • std::optional<int> containing the MTU value if successfully determined.
  • std::nullopt if:
    • The socket is not bound
    • The local interface cannot be resolved
    • The OS query fails
Exceptions
SocketExceptionIf a low-level socket operation (e.g., getsockname()) fails.
Note
This method returns the MTU of the local sending interface, not of any remote peer.
On some platforms, this requires the socket to be explicitly bound or connected.
See also
write(), bind(), connect(), getLocalSocketAddress(), getBoundLocalIp(), ipAddressesEqual()

◆ getMulticastInterface()

std::string jsocketpp::MulticastSocket::getMulticastInterface ( ) const
inlinenodiscard

Get the currently selected egress interface for multicast transmissions.

Returns the human-friendly identifier that this object currently holds as the default outgoing multicast interface, as last set via setMulticastInterface(const std::string&). This is a cached value intended for diagnostics and UI; it does not perform a fresh system query.

Possible return forms (depending on how the interface was selected):

  • IPv4 egress: the interface’s IPv4 literal address (e.g., "192.168.1.5").
  • IPv6 egress: a numeric interface index as a decimal string (e.g., "12"), or on POSIX the interface name originally provided (e.g., "eth0").
  • Empty string (""): no explicit egress configured — the system defaults are in effect (IPv4: INADDR_ANY; IPv6: index 0).
Returns
The current multicast egress selector (IPv4 address, IPv6 name/index as a string), or an empty string if the system default is in use.
Precondition
  • None. This is a read-only accessor.
Postcondition
Note
  • This method returns the value cached by this object when setMulticastInterface(const std::string&) last succeeded. It does not re-read kernel state. If code outside this class (e.g., direct calls to setMulticastInterfaceIPv4(in_addr) or setMulticastInterfaceIPv6(unsigned int)) changes the egress after that, this cached string may no longer reflect the OS setting.
  • The return format mirrors the input you supplied: IPv4 address for IPv4 egress, decimal index (or POSIX name) for IPv6 egress, or "" for default routing.
  • This accessor is about multicast egress selection only; it does not imply any group membership. Use join/leave APIs to manage membership.
Related options
// Default (no explicit egress)
assert(sock.getMulticastInterface().empty());
// Choose IPv4 egress by address
sock.setMulticastInterface("192.0.2.10");
assert(sock.getMulticastInterface() == "192.0.2.10");
// POSIX: choose IPv6 egress by name (or use a numeric index string on any platform)
sock.setMulticastInterface("eth0"); // POSIX name
// or: sock.setMulticastInterface("12"); // numeric index string
auto current = sock.getMulticastInterface(); // "eth0" or "12"
MulticastSocket(Port localPort, std::string_view localAddress, std::optional< std::size_t > recvBufferSize=std::nullopt, std::optional< std::size_t > sendBufferSize=std::nullopt, std::optional< std::size_t > internalBufferSize=std::nullopt, bool reuseAddress=true, int soRecvTimeoutMillis=-1, int soSendTimeoutMillis=-1, bool nonBlocking=false, bool dualStack=true, bool autoBind=true)
Constructs a fully configurable multicast socket for receiving and sending datagrams.
Definition MulticastSocket.cpp:7
std::string getMulticastInterface() const
Get the currently selected egress interface for multicast transmissions.
Definition MulticastSocket.hpp:478
void setMulticastInterface(const std::string &iface)
Select the default outgoing interface for multicast transmissions.
Definition MulticastSocket.cpp:20

◆ getRemoteIp()

std::string DatagramSocket::getRemoteIp ( bool convertIPv4Mapped) const
nodiscard

Return the remote peer IP address for this socket.

Produces the textual IP address (IPv4 or IPv6) of the current remote endpoint. The source of truth is:

  • Connected sockets: use the cached peer if available; otherwise perform one getpeername() to query the OS.
  • Unconnected sockets: return the last-seen sender if your receive path has cached one; otherwise this method fails because no remote is known yet.

When convertIPv4Mapped is true and the address is IPv6 IPv4-mapped (::ffff:a.b.c.d), the result is converted to an IPv4 literal (a.b.c.d).

Parameters
[in]convertIPv4MappedConvert IPv4-mapped IPv6 addresses to IPv4 text if true.
Returns
std::string Remote IP address in presentation form.
Precondition
The socket must be open (isOpen() == true).
Exceptions
SocketException
  • If the socket is not open.
  • If the socket is unconnected and no last-seen sender is cached.
  • If getpeername() is needed (connected, no cache) and it fails; the exception carries GetSocketError() and SocketErrorMessage(GetSocketError()).
Note
Complexity: O(1) when the peer is cached; otherwise one getpeername() call.
Thread-safety: call from the socket’s owning thread; do not race with disconnect() or close().
s.connect("2001:db8::10", 5353, 1000);
std::string ip = s.getRemoteIp(true); // e.g., "2001:db8::10"
std::string getRemoteIp(bool convertIPv4Mapped) const
Return the remote peer IP address for this socket.
Definition DatagramSocket.cpp:1751

◆ getRemotePort()

Port DatagramSocket::getRemotePort ( ) const
nodiscard

Return the remote peer UDP port for this socket.

Obtains the numeric port of the current remote endpoint. The source of truth is:

  • Connected sockets: use the cached peer (if available); otherwise perform a single getpeername() to query the OS.
  • Unconnected sockets: return the last-seen sender if your receive path has cached one; otherwise this method fails because no remote is known yet.
Returns
Port The remote UDP port number.
Precondition
isOpen() == true.
Exceptions
SocketException
  • If the socket is not open.
  • If the socket is unconnected and no last-seen sender is cached.
  • If getpeername() is required (connected, no cache) and it fails; the exception carries GetSocketError() and SocketErrorMessage(GetSocketError()).
Note
Complexity: O(1) when the remote is cached; otherwise one getpeername() call.
Thread-safety: intended for the socket’s owning thread. Do not call concurrently with disconnect() or close() or other operations that mutate connection state.
s.connect("203.0.113.7", 9999, 1000);
Port rp = s.getRemotePort(); // e.g., 9999
Port getRemotePort() const
Return the remote peer UDP port for this socket.
Definition DatagramSocket.cpp:1760

◆ getRemoteSocketAddress()

std::string DatagramSocket::getRemoteSocketAddress ( bool convertIPv4Mapped) const
nodiscard

Return the remote endpoint as a single "ip:port" string.

Formats the current remote endpoint into a presentation string. The source of truth is:

  • Connected sockets: use the cached peer if available; otherwise perform at most one getpeername() to obtain it.
  • Unconnected sockets: use the last-seen sender cached by receive paths; if none is available, the method fails because no remote is known yet.

When convertIPv4Mapped is true and the address is an IPv6 IPv4-mapped form (::ffff:a.b.c.d), the IP portion is converted to an IPv4 literal (a.b.c.d) before concatenation. If your IP formatter brackets IPv6 addresses, the result may look like "[2001:db8::1]:5353".

Parameters
[in]convertIPv4MappedIf true, convert IPv4-mapped IPv6 addresses to IPv4 text before building the result.
Returns
std::string The remote endpoint string, e.g., "192.0.2.10:54321" or "[2001:db8::1]:54321".
Precondition
The socket must be open (isOpen() == true).
Exceptions
SocketException
  • If the socket is not open.
  • If the socket is unconnected and no last-seen sender is cached.
  • If getpeername() is required (connected, no cache) and it fails; the exception carries GetSocketError() and SocketErrorMessage(GetSocketError()).
Note
Complexity: O(1) when the remote is cached; otherwise at most one getpeername() call.
Thread-safety: call from the socket’s owning thread; do not race with disconnect() or close().
s.connect("example.net", 5353, 2000);
auto ep = s.getRemoteSocketAddress(true); // e.g., "[2001:db8::10]:5353"
std::string getRemoteSocketAddress(bool convertIPv4Mapped) const
Return the remote endpoint as a single "ip:port" string.
Definition DatagramSocket.cpp:1769

◆ hasDestination()

bool jsocketpp::DatagramPacket::hasDestination ( ) const
inlinenodiscardnoexcept

Report whether this packet specifies an explicit destination (address + port).

Returns true if the packet’s destination fields are set to a usable value for sending: a non-blank address (not just whitespace) and a non-zero UDP port. This is a syntactic check only; it does not validate that the address string is a resolvable host/IP or that the port is reachable.

Typical uses:

  • In DatagramSocket::write(const DatagramPacket&), choose between sending to the socket’s connected peer (when this returns false) or sending to the packet’s explicit destination via sendto (when this returns true).
  • After a receive, indicates whether the source endpoint fields (address, port) were filled.
Returns
true if address contains any non-whitespace character and port != 0; otherwise false.
p.buffer.assign(data.begin(), data.end());
// No destination yet:
assert(!p.hasDestination());
// Set destination for send:
p.address = "2001:db8::1";
p.port = 5353;
assert(p.hasDestination());
std::vector< char > buffer
Data buffer for the packet payload.
Definition DatagramPacket.hpp:56
Port port
Remote UDP port for the destination/source.
Definition DatagramPacket.hpp:70
DatagramPacket(const size_t size=0)
Construct an empty DatagramPacket with a specified buffer size.
Definition DatagramPacket.hpp:76
std::string address
Remote address (IPv4/IPv6) for the destination/source.
Definition DatagramPacket.hpp:63
bool hasDestination() const noexcept
Report whether this packet specifies an explicit destination (address + port).
Definition DatagramPacket.hpp:161

◆ hasPendingData()

bool DatagramSocket::hasPendingData ( int timeoutMillis) const

Check if the socket is readable within a timeout (no data is consumed).

Since
1.0

Waits until the socket becomes readable and returns whether at least one datagram is ready to be received. This call does not read or consume data; it only checks readiness. A negative timeoutMillis blocks indefinitely. A zero timeout performs a non-blocking poll.

Implementation uses poll on POSIX and WSAPoll on Windows (preferred over select to avoid FD_SETSIZE limits and provide better EINTR semantics).

Parameters
[in]timeoutMillisTimeout in milliseconds. < 0 = infinite, 0 = immediate, > 0 = bounded wait.
Returns
true if the socket is readable within the timeout; false on timeout (no data ready).
Exceptions
SocketExceptionIf the socket is not open or if the readiness API reports an error (error code/message via SocketErrorMessage).
Precondition
The socket has been successfully created/opened.
Postcondition
No data is consumed from the socket; the readability state may change due to races typical of readiness APIs (i.e., data could be gone by the time you attempt to read).
Note
Prefer calling this as a guard before best-effort reads with per-call timeouts (e.g., readAtMostWithTimeout can delegate to this check).

◆ isBound()

bool jsocketpp::DatagramSocket::isBound ( ) const
inlinenodiscardnoexcept

Indicates whether the datagram socket has been explicitly bound to a local address or port.

Returns true if the socket has successfully completed a call to one of the bind() overloads. Binding is optional for UDP sockets, but is commonly required for:

  • Receiving datagrams on a specific port (e.g., UDP server or listener)
  • Specifying a fixed source port (e.g., for NAT traversal or P2P scenarios)
  • Selecting a specific local interface in multihomed systems
  • Participating in multicast or broadcast communication
Note
A datagram socket can only be bound once. Attempting to bind again will throw.
If the socket was constructed with a port but bind() is never called, it remains unbound.
Binding must occur before calling connect() or sending datagrams from an unconnected socket.

Example

sock.bind(12345);
if (sock.isBound()) {
std::cout << "Listening on " << sock.getLocalSocketAddress() << "\n";
}
bool isBound() const noexcept
Indicates whether the datagram socket has been explicitly bound to a local address or port.
Definition DatagramSocket.hpp:880
Returns
true if the socket has been bound to a local address/port, false otherwise.
See also
bind(), isConnected(), getLocalSocketAddress()

◆ isClosed()

bool jsocketpp::DatagramSocket::isClosed ( ) const
inlinenodiscardnoexcept

Checks whether the datagram socket has been closed or is otherwise invalid.

Returns true if the socket is no longer usable—either because it was explicitly closed via close(), or because it was never successfully initialized (i.e., holds an invalid file descriptor).

This method does not perform any system-level query. It simply checks whether the internal socket descriptor equals INVALID_SOCKET. This is the standard invariant for resource management in the jsocketpp UDP API.

Common Scenarios

  • The socket was default-initialized or failed during construction
  • The socket was explicitly closed via close()
  • The socket was moved-from, leaving the source in a valid but unusable state
Note
Once a datagram socket is closed, it cannot be reused. Create a new instance to open a new socket.
Returns
true if the socket is closed or invalid, false if it is open and usable.

Example

assert(!sock.isClosed());
sock.close();
assert(sock.isClosed()); // ✅
Cross-platform UDP socket class with Java-style interface.
Definition DatagramSocket.hpp:484
See also
close(), isConnected(), isBound(), getSocketFd()

◆ isConnected()

bool jsocketpp::DatagramSocket::isConnected ( ) const
inlinenodiscardnoexcept

Indicates whether the datagram socket is connected to a specific remote peer.

Returns true if the socket has been successfully connected to a remote address and port using the connect() method. While UDP is a connectionless protocol, invoking connect() on a datagram socket enables connection-oriented semantics:

  • Filters incoming datagrams to only accept from the connected peer
  • Allows use of send() / recv() instead of sendto() / recvfrom()
  • Enables simplified calls like write("message") or read<T>()
Note
This method reflects the internal connection state as tracked by the library.
It does not verify whether the remote host is reachable or alive.
Unconnected sockets may still send and receive using write(host, port) or write(DatagramPacket).

Example

DatagramSocket sock("example.com", 9999);
sock.connect();
if (sock.isConnected()) {
sock.write("ping");
}
Returns
true if the socket has been logically connected to a peer, false otherwise.
See also
connect(), write(std::string_view), read<T>(), disconnect()

◆ isValid()

bool jsocketpp::DatagramSocket::isValid ( ) const
inlinenodiscardnoexcept

Checks whether the datagram socket is valid and ready for use.

Returns true if the socket has a valid file descriptor and has not been closed or moved-from. A valid datagram socket can be used for sending and receiving UDP packets, though it may or may not be bound or connected.

This method performs a quick, local check:

  • It does not verify whether the socket is bound (see isBound())
  • It does not verify whether the socket is connected (see isConnected())
  • It does not query the operating system or socket state

Use Cases

  • Guarding against use-after-close
  • Early validation in test or utility code
  • Precondition checks before bind() or connect()

Implementation Details

Returns
true if the socket is open and usable; false if it was closed, moved-from, or failed to initialize.
Note
A valid socket may be unbound or unconnected. Use isBound() and isConnected() to query those states.

Example

DatagramSocket sock("example.com", 9999);
assert(sock.isValid());
sock.connect();
sock.close();
assert(!sock.isValid()); // ✅ socket no longer usable
See also
isBound(), isConnected(), close(), getSocketFd()

◆ joinGroup()

void MulticastSocket::joinGroup ( const std::string & groupAddr,
const std::string & iface )

Join a multicast group on an optional interface (string-friendly).

Adds this socket to the multicast group identified by groupAddr, optionally scoping the membership to a specific local interface indicated by iface. The method accepts human-friendly identifiers and performs resolution and validation before delegating to the OS via setsockopt.

Accepted forms

  • groupAddr:
    • IPv4 literal (e.g., "239.1.2.3") or hostname that resolves to IPv4.
    • IPv6 literal (e.g., "ff15::abcd") or hostname that resolves to IPv6.
    • Must resolve to a multicast address (IPv4 224.0.0.0/4 or IPv6 ff00::/8).
  • iface (optional selector of the local interface used for membership):
    • IPv4 membership: IPv4 literal of the interface’s unicast address (e.g., "192.0.2.10"). Empty selects the default (INADDR_ANY).
    • IPv6 membership: decimal interface index as a string (e.g., "12"). On POSIX, an interface name (e.g., "eth0") is also accepted and converted via if_nametoindex(). Empty selects index 0 (default). On Windows, interface names are not supported; use a numeric index.

Behavior

Notes

  • This method does not select the egress interface for outbound traffic; use setMulticastInterface(const std::string&) (or the per-family variants) to choose where your sends go. Membership here controls what you receive.
  • For link-local IPv6 groups (ff02::/16), specifying a correct interface index is often required by the OS; prefer a non-empty iface in that case.
  • Repeat joins of the same (group, interface) may be ignored or rejected by the OS depending on the stack; behavior is implementation-defined.
Parameters
[in]groupAddrMulticast group (literal or resolvable name), IPv4 or IPv6.
[in]ifaceOptional interface selector as described above; empty uses the default.
Exceptions
SocketException
  • groupAddr is empty or does not resolve to a multicast address.
  • iface is malformed (e.g., bad IPv4 literal; unknown POSIX name; non-numeric index string on Windows).
  • Name resolution fails (exception carries the getaddrinfo code/message).
  • The underlying membership call fails:
    • IPv4: setsockopt(IP_ADD_MEMBERSHIP)
    • IPv6 (POSIX): setsockopt(IPV6_JOIN_GROUP)
    • IPv6 (Windows): setsockopt(IPV6_ADD_MEMBERSHIP)
Related
// IPv4: join on default interface
sock.joinGroup("239.1.2.3", "");
// IPv4: join on a specific local interface address
sock.joinGroup("239.1.2.3", "192.0.2.10");
// IPv6: join using numeric interface index (works on all platforms)
sock.joinGroup("ff15::feed", "12");
// POSIX only: join using interface name
sock.joinGroup("ff15::feed", "eth0");

◆ leaveGroup()

void MulticastSocket::leaveGroup ( const std::string & groupAddr,
const std::string & iface = "" )

Leave a multicast group on an optional interface (string-friendly).

Removes this socket’s membership from the multicast group identified by groupAddr. The interface used for the leave operation can be selected via iface and follows the same conventions as joinGroup.

Accepted forms

  • groupAddr:
    • IPv4 literal (e.g., "239.1.2.3") or hostname that resolves to IPv4.
    • IPv6 literal (e.g., "ff15::abcd") or hostname that resolves to IPv6.
    • Must resolve to a multicast address (IPv4 224.0.0.0/4, IPv6 ff00::/8).
  • iface (optional; selects the local interface whose membership is removed):
    • IPv4 leave: IPv4 literal of the interface’s unicast address (e.g., "192.0.2.10"). Empty string selects the default interface (INADDR_ANY).
    • IPv6 leave: decimal interface index as a string (e.g., "12"). On POSIX, an interface name (e.g., "eth0") is also accepted and mapped via if_nametoindex(). Empty string selects index 0 (system default). On Windows, names are not supported; use a numeric index.

Behavior

  • Resolves groupAddr to either an in_addr or in6_addr via a fast literal path first, and otherwise through the project resolver (resolveAddress).
  • Validates that the resolved address is multicast (IN_MULTICAST / IN6_IS_ADDR_MULTICAST).
  • Interprets iface as described above to obtain the IPv4 interface address or IPv6 interface index used when the membership was created.
  • Delegates to centralized option helpers:
    • IPv4: setsockopt(IP_DROP_MEMBERSHIP) via leaveGroupIPv4(in_addr group, in_addr iface)
    • IPv6 (POSIX): setsockopt(IPV6_LEAVE_GROUP) via leaveGroupIPv6(in6_addr group, unsigned ifindex)
    • IPv6 (Windows): setsockopt(IPV6_DROP_MEMBERSHIP) via leaveGroupIPv6(...)

Notes

  • The interface provided to leave should match the one used to join the group on this socket. If it does not, some stacks return an error (for example EADDRNOTAVAIL) or ignore the request.
  • This method affects only membership (what the socket can receive). It does not change the egress interface for sending; use setMulticastInterface(...) for that.
  • Repeated leaves for the same (group, interface) may be ignored or may fail depending on the OS; behavior is implementation-defined.
Parameters
[in]groupAddrMulticast group to leave (literal or resolvable name), IPv4 or IPv6.
[in]ifaceOptional interface selector as described above; default is the empty string, which uses the system default (IPv4 INADDR_ANY, IPv6 index 0).
Precondition
  • The socket was previously joined to the specified group on the selected interface.
Postcondition
  • The socket is no longer a member of the specified group on that interface. Internal caches tracking the “current” group/interface may be cleared if they match.
Exceptions
SocketException
  • groupAddr is empty or does not resolve to a multicast address.
  • iface is malformed (invalid IPv4 literal, unknown POSIX interface name, or non-numeric index on Windows where names are unsupported).
  • Name resolution fails; the exception carries the getaddrinfo code/message.
  • The underlying membership removal fails (e.g., ENOTSOCK, EINVAL, EADDRNOTAVAIL, ENOPROTOOPT, or Windows equivalents) when invoking:
    • IPv4: IP_DROP_MEMBERSHIP
    • IPv6 (POSIX): IPV6_LEAVE_GROUP
    • IPv6 (Windows): IPV6_DROP_MEMBERSHIP
Related
// IPv4: leave on default interface
sock.leaveGroup("239.1.2.3");
// IPv4: leave on a specific local interface address
sock.leaveGroup("239.1.2.3", "192.0.2.10");
// IPv6: leave using numeric interface index (any platform)
sock.leaveGroup("ff15::feed", "12");
// POSIX-only: leave using interface name
sock.leaveGroup("ff15::feed", "eth0");

◆ MulticastSocket()

MulticastSocket::MulticastSocket ( Port localPort,
std::string_view localAddress,
std::optional< std::size_t > recvBufferSize = std::nullopt,
std::optional< std::size_t > sendBufferSize = std::nullopt,
std::optional< std::size_t > internalBufferSize = std::nullopt,
bool reuseAddress = true,
int soRecvTimeoutMillis = -1,
int soSendTimeoutMillis = -1,
bool nonBlocking = false,
bool dualStack = true,
bool autoBind = true )

Constructs a fully configurable multicast socket for receiving and sending datagrams.

This advanced constructor provides complete control over the configuration of a multicast UDP socket, including binding behavior, buffer sizes, timeouts, and dual-stack support. It is designed for power users who need fine-grained socket tuning prior to joining one or more multicast groups using joinGroup().

Unlike simpler constructors, this overload supports use cases such as:

  • Binding to a specific local interface (e.g., "192.168.1.5" or "::1")
  • Using system-assigned ephemeral ports (by passing localPort = 0)
  • Tuning performance and memory characteristics with custom buffer sizes
  • Enabling non-blocking mode for asynchronous usage
  • Configuring receive/send timeouts for socket operations
  • Enabling dual-stack mode for IPv4-mapped IPv6 support

No multicast group is joined automatically — you must call joinGroup() after construction.

Parameters
[in]localPortThe local port to bind to. Use 0 to request an ephemeral port assigned by the OS.
[in]localAddressOptional local interface or IP address to bind to. Common values:
  • "0.0.0.0": any IPv4 interface
  • "::": any IPv6 interface
  • A specific interface address (e.g., "192.168.1.10")
[in]recvBufferSizeOptional size of the OS-level receive buffer, in bytes (e.g., 4096). If std::nullopt, the default size is used.
[in]sendBufferSizeOptional size of the OS-level send buffer, in bytes. If std::nullopt, the default is used.
[in]internalBufferSizeOptional size of the internal user-space buffer used by read() and related methods.
[in]reuseAddressWhether to enable SO_REUSEADDR so multiple sockets can bind to the same port (useful for multiple receivers on the same machine).
[in]soRecvTimeoutMillisReceive timeout in milliseconds. Use -1 to disable.
[in]soSendTimeoutMillisSend timeout in milliseconds. Use -1 to disable.
[in]nonBlockingIf true, the socket is set to non-blocking mode after creation.
[in]dualStackEnables IPv4-mapped IPv6 support when using "::" bind addresses. Has no effect for IPv4-only sockets.
[in]autoBindIf true, the socket will automatically call bind() to the given address and port. If false, you must call bind() manually before using the socket.
Exceptions
SocketExceptionIf socket creation, binding, or option setting fails for any reason.
Note
This constructor does not automatically join a multicast group. Use joinGroup() after construction to receive multicast traffic.

Example

using namespace jsocketpp;
4446, // bind to port 4446
"::", // bind to all interfaces (IPv6)
4096, // OS receive buffer size
4096, // OS send buffer size
8192, // internal buffer size
true, // reuse address (SO_REUSEADDR)
2000, // receive timeout (ms)
2000, // send timeout (ms)
false, // blocking mode
true, // dual stack enabled
true // auto-bind
);
sock.joinGroup("ff12::1234"); // Join multicast group explicitly
A C++ socket library providing Java-style networking interfaces.
Definition BufferView.hpp:16
See also
joinGroup()
leaveGroup()
setMulticastInterface()
setTimeToLive()
setLoopbackMode()

◆ operator=() [1/2]

DatagramSocket & jsocketpp::DatagramSocket::operator= ( const DatagramSocket & )
delete

Copy assignment operator (deleted) for DatagramSocket.

The copy assignment operator is explicitly deleted to prevent assignment between DatagramSocket instances. This class manages a native socket file descriptor and internal buffers, which must have clear ownership semantics.

Allowing copy assignment would result in:

  • Multiple objects referring to the same underlying socket
  • Risk of double-close or concurrent misuse
  • Broken RAII guarantees and undefined behavior

This deletion enforces safe, move-only usage patterns consistent across the socket library.

Note
Use move assignment (operator=(DatagramSocket&&)) if you need to transfer ownership.
DatagramSocket a(12345);
b = a; // ❌ Compilation error (copy assignment is deleted)
See also
operator=(DatagramSocket&&) noexcept

◆ operator=() [2/2]

DatagramSocket & jsocketpp::DatagramSocket::operator= ( DatagramSocket && rhs)
inlinenoexcept

Move assignment operator for DatagramSocket.

Releases any resources owned by this socket instance and transfers ownership from another DatagramSocket object (rhs). After the operation:

  • This socket adopts the file descriptor, buffer, and internal state from rhs
  • The source object is left in a valid but unspecified state (INVALID_SOCKET)
  • Existing resources in the destination socket are released via close()

Ownership Transferred

Notes

Note
This method is noexcept and safe to use in container scenarios (e.g., std::vector<DatagramSocket>).
After the move, rhs will be left in an uninitialized state and should not be used except for destruction or reassignment.
If close() throws during cleanup, the exception is suppressed to preserve noexcept guarantees.

Example

DatagramSocket a(12345);
b = std::move(a); // b now owns the socket previously held by a
assert(!a.isValid());
assert(b.isValid());
bool isValid() const noexcept
Checks whether the datagram socket is valid and ready for use.
Definition DatagramSocket.hpp:3955
Parameters
[in,out]rhsThe source DatagramSocket to move from.
Returns
Reference to the updated *this object.
See also
DatagramSocket(DatagramSocket&&) noexcept
close(), isValid()

◆ peek()

DatagramReadResult DatagramSocket::peek ( DatagramPacket & packet,
bool allowResize = true,
const DatagramReadOptions & opts = {} ) const
nodiscard

Peek at the next UDP datagram without consuming it (single receive with MSG_PEEK).

Since
1.0

Copies up to packet.buffer.size() bytes from the next datagram into packet.buffer using a single kernel receive with MSG_PEEK so the datagram remains queued. The method:

  • Never removes the datagram from the kernel queue.
  • Can optionally grow packet.buffer before peeking when allowResize is true: it first tries to probe the next datagram size and, if successful, resizes exactly to that size (clamped to MaxDatagramPayloadSafe); otherwise it uses a safe default.
  • Reports whether the datagram would be truncated via DatagramReadResult::truncated and, when available, returns the full datagram size (datagramSize).
  • Does not update the internally tracked “last remote.” If you need that, do a real read.

On POSIX, uses recvmsg with MSG_PEEK; on Linux it also sets MSG_TRUNC so the return value reflects the full datagram size even when the user buffer is smaller. On Windows, uses recvfrom with MSG_PEEK.

Parameters
[in,out]packetDestination DatagramPacket. Its buffer is the peek target; when allowResize is true and the size is known, it may be resized prior to the peek. When opts.resolveNumeric is true, packet.address and packet.port are filled.
[in]allowResizeWhen true and a size probe succeeds, grow packet.buffer to fit exactly (clamped to MaxDatagramPayloadSafe). If false and the buffer is empty, the call throws.
[in]optsRead options. resolveNumeric is honored; recvFlags is OR’ed with MSG_PEEK. Other fields (e.g., updateLastRemote) are ignored for peek (no side-effects).
Returns
DatagramReadResult with:
  • bytes Number of bytes copied into packet.buffer (≤ its capacity),
  • datagramSize Full datagram size when known (0 if unknown on this platform/path),
  • truncated True if the datagram is larger than the provided capacity,
  • src/srcLen Sender address (not stored as “last remote”).
Exceptions
SocketExceptionIf the socket is not open; packet.buffer is empty and allowResize is false; OS-level errors occur (message via SocketErrorMessage).
SocketTimeoutExceptionIf the socket is non-blocking and no data is available (would-block), or a configured receive timeout elapses (platform-mapped).
Precondition
The socket has been successfully created/opened.
Postcondition
No datagram has been removed from the receive queue; packet.buffer contains a copy of the leading bytes.
Note
A zero-length datagram is valid: peeking it yields bytes == 0 and does not indicate “connection closed.”

◆ read() [1/3]

template<typename T, std::enable_if_t< detail::is_fixed_buffer_v< T >, int > = 0>
T jsocketpp::DatagramSocket::read ( const DatagramReadOptions & opts = {}) const
inlinenodiscard

Read one UDP datagram into a fixed-size, contiguous byte container (zero allocation).

Since
1.0
Template Parameters
TA fixed-size, contiguous byte-like container (e.g., std::array<char, N>, std::array<unsigned char, N>, std::array<std::byte, N>) exposing data() and size().

Performs exactly one receive and copies up to T::size() bytes into the returned container. Trailing bytes remain value-initialized (typically zero) if the datagram is shorter. Truncation behavior is controlled by opts.errorOnTruncate:

  • If a reliable size probe is available and the datagram would not fit while opts.errorOnTruncate is true, the function throws before reading so the datagram stays queued.
  • Otherwise, if truncation occurs and opts.errorOnTruncate is true, it throws after the read.
  • If opts.errorOnTruncate is false, the payload is truncated to T::size() without error. When opts.updateLastRemote is true, the internally tracked “last remote” is updated. The requested copy length is always clamped to MaxDatagramPayloadSafe.
Parameters
[in]optsRead options controlling preflight, truncation policy, and sender bookkeeping.
Returns
The fixed-size container T containing the received bytes in its leading elements. Any unused tail remains value-initialized.
Exceptions
SocketExceptionIf the socket is not open, on OS-level errors (message via SocketErrorMessage), or when truncation is disallowed by opts.errorOnTruncate.
SocketTimeoutExceptionIf a receive timeout elapses before any datagram is available, or when the socket is non-blocking and no data is available.
Precondition
The socket has been successfully created/opened.
Postcondition
On success, the first n bytes of the returned container hold the payload, where nT::size(). If opts.updateLastRemote is true, the internal “last remote” reflects the sender.
Note
Prefer opts.errorOnTruncate = true with DatagramReceiveMode::PreflightSize for strict no-truncation behavior when supported by the platform.
Example
std::array<char, 1500> buf = sock.read<std::array<char,1500>>({
.errorOnTruncate = true,
});

◆ read() [2/3]

template<typename T, std::enable_if_t< detail::is_dynamic_buffer_v< T >, int > = 0>
T jsocketpp::DatagramSocket::read ( const DatagramReadOptions & opts = {},
std::size_t minCapacity = DefaultDatagramReceiveSize ) const
inlinenodiscard

Read one UDP datagram into a dynamically resizable, contiguous byte container (zero-copy into caller storage).

Since
1.0
Template Parameters
TA contiguous, dynamically resizable byte-like container (e.g., std::string, std::vector<char>, std::vector<std::byte>, std::pmr::string) that provides data(), size(), and resize().

Allocates a buffer in T, receives exactly one datagram into it, and then shrinks the container to the number of bytes actually received. Capacity is chosen as follows:

  • Start from minCapacity, clamped to MaxDatagramPayloadSafe. If minCapacity is 0, it is treated as 1 to allow clean reception of zero-length datagrams.
  • If size preflight is requested (see opts.mode) or strict no-truncation is desired (opts.errorOnTruncate == true), the next datagram size is probed. On success, the container is grown to the exact datagram size (clamped to MaxDatagramPayloadSafe) to avoid truncation and extra copies.

The actual copy is performed with a single kernel receive via readInto(...). If truncation occurs and opts.errorOnTruncate == true, readInto(...) will throw according to its policy (either before the read, when size is known, or after the read otherwise). On success, the container is shrunk to the number of bytes received. No null terminator is appended automatically.

Parameters
[in]optsRead options (preflight mode, truncation policy, sender bookkeeping).
[in]minCapacityMinimum initial capacity to allocate before reading. Clamped to MaxDatagramPayloadSafe.
Returns
The container T holding the received payload (size equals the number of bytes received).
Exceptions
SocketExceptionIf the socket is not open, OS-level errors occur (message via SocketErrorMessage), or truncation is disallowed by opts.errorOnTruncate and would occur.
SocketTimeoutExceptionIf a configured receive timeout elapses before any datagram is received, or when the socket is non-blocking and no data is available (would-block).
Precondition
The socket has been successfully created/opened.
Postcondition
On success, the returned container’s size() equals the number of bytes received; its content is the payload.
Note
Prefer enabling strict no-truncation (opts.errorOnTruncate = true) together with size preflight (opts.mode = DatagramReceiveMode::PreflightSize) when available, so overlarge datagrams are rejected before data is consumed.
Example
ro.errorOnTruncate = true;
std::string payload = sock.read<std::string>(ro); // exact-size allocation when preflight succeeds
Options controlling a single UDP receive operation.
Definition DatagramSocket.hpp:136
bool errorOnTruncate
When true, the read fails if the incoming datagram would be truncated.
Definition DatagramSocket.hpp:220
DatagramReceiveMode mode
Datagram sizing policy to use during receive.
Definition DatagramSocket.hpp:143

◆ read() [3/3]

DatagramReadResult DatagramSocket::read ( DatagramPacket & packet,
const DatagramReadOptions & opts ) const

Read one UDP datagram into a DatagramPacket with optional growth/shrink and strict truncation policy.

Since
1.0

Receives exactly one datagram and copies its payload into packet.buffer. Behavior is governed by opts:

  • If a size preflight succeeds and opts.allowGrow is true, the buffer may be resized up front (clamped to MaxDatagramPayloadSafe) to fit the datagram exactly.
  • If the buffer is smaller than the datagram and opts.errorOnTruncate is true, the call throws before reading when size is known; otherwise it throws after the read if truncation occurred.
  • If opts.allowShrink is true and no truncation occurred, the buffer may be resized down to the exact number of bytes received.
  • If opts.updateLastRemote is true, the internally tracked “last remote” is updated to the sender.
  • If opts.resolveNumeric is true, packet.address and packet.port are filled with the sender’s numeric host and port. Exactly one kernel receive is performed for the payload copy; all requests are clamped to MaxDatagramPayloadSafe.
Implementation notes
Uses a size probe when available (internal::nextDatagramSize). When the size is known and opts.errorOnTruncate is true, the method fails early without consuming the datagram. The actual copy is performed with a single recv/recvmsg call via the internal backbone.
Parameters
[in,out]packetDestination datagram container. On input, its buffer capacity limits the copy unless opts.allowGrow enables pre-read resizing. On success, the first result.bytes bytes contain the payload; address/port fields are updated when requested.
[in]optsRead options controlling preflight, capacity growth/shrink, truncation policy, sender bookkeeping, and numeric address resolution.
Returns
A DatagramReadResult with:
  • bytes Number of bytes copied into packet.buffer.
  • datagramSize Full datagram size when known (0 if unknown on this platform/path).
  • truncated True if the datagram did not fully fit the destination buffer.
Exceptions
SocketExceptionIf the socket is not open, arguments are invalid, OS-level receive errors occur (message via SocketErrorMessage), or truncation is disallowed by opts.errorOnTruncate.
SocketTimeoutExceptionIf a configured receive timeout elapses before any datagram is received, or when the socket is non-blocking and no data is available.
Precondition
The socket has been successfully created/opened.
Postcondition
On success, packet.buffer holds the received payload (possibly resized per opts.allowShrink). When opts.updateLastRemote is true, the internal “last remote” reflects the sender.
Note
When size cannot be probed and opts.errorOnTruncate is false, oversized datagrams are truncated by the kernel and the tail is lost. Enable opts.errorOnTruncate for strict no-truncation behavior.
Example: grow to exact size, reject truncation
ro.allowGrow = true;
ro.errorOnTruncate = true;
auto r = sock.read(pkt, ro);
std::string_view payload(pkt.buffer.data(), r.bytes);
bool allowGrow
Whether the packet buffer may grow before receive (applies to DatagramPacket).
Definition DatagramSocket.hpp:152
Example: fixed buffer, allow truncation
DatagramPacket small(512);
op.errorOnTruncate = false;
auto r2 = sock.read(small, op);
See also
readInto(std::span<char>, const DatagramReadOptions&) for zero-allocation reads into caller buffers.
readAvailable() for returning the full datagram as a string (tries to avoid truncation).
readAtMost(std::span<char>, const DatagramReadOptions&) for single-recv best-effort reads without preflight.
DatagramReadOptions for all configurable policies.

◆ readAtMost()

std::size_t DatagramSocket::readAtMost ( std::span< char > out,
const DatagramReadOptions & opts = {} ) const

Read up to out.size() bytes from the next UDP datagram into a caller-provided buffer (no allocation).

Since
1.0

Performs exactly one receive with at-most semantics:

  • If the incoming datagram is smaller than out, only that many bytes are written.
  • If the datagram is larger than out, only the first out.size() bytes are written and the remainder of the datagram is discarded by the kernel (standard UDP truncation).

This API enforces a single recv(from) with no extra syscalls by using DatagramReceiveMode::NoPreflight for the actual receive (any opts.mode setting is overridden for this method). On unconnected sockets, when opts.updateLastRemote == true, the internally tracked “last remote” endpoint is updated to the sender.

Blocking/timeout behavior:

  • In blocking mode, the call waits until a datagram arrives or a configured receive timeout elapses. On timeout, SocketTimeoutException is thrown.
  • In non-blocking mode with no data available, a SocketTimeoutException is also thrown (would-block mapped).
Parameters
[out]outDestination span receiving at most out.size() bytes.
[in]optsRead options; fields other than mode are honored. The effective mode is forced to DatagramReceiveMode::NoPreflight to preserve single-recv semantics.
Returns
Number of bytes actually written to out (0 if out is empty).
Exceptions
SocketExceptionIf the socket is not open, on argument errors, or on other OS-level receive errors (message via SocketErrorMessage).
SocketTimeoutExceptionIf a configured receive timeout elapses before any datagram is received, or when the socket is non-blocking and no data is available.
Precondition
The socket has been successfully created/opened.
Postcondition
On success, exactly the returned number of bytes have been written to out. For unconnected sockets, when opts.updateLastRemote == true, the internal “last remote” reflects the sender of this datagram.
Note
This function never allocates and never enlarges the caller’s buffer.
Warning
If out is smaller than the datagram, the tail of that datagram is dropped (cannot be recovered).
Example
std::array<char, 1500> buf{};
const std::size_t n = sock.readAtMost(std::span<char>(buf.data(), buf.size()), ro);
std::string_view payload(buf.data(), n);
See also
readAtMost(std::size_t) for a convenience overload that allocates and returns a string.
readAvailable(std::span<char>, const DatagramReadOptions&) when you need no-truncation semantics.
readInto(void*, std::size_t, const DatagramReadOptions&) for the lower-level primitive.

◆ readAtMostWithTimeout()

std::string DatagramSocket::readAtMostWithTimeout ( std::size_t n,
int timeoutMillis ) const
nodiscard

Read up to n bytes from the next UDP datagram, waiting up to timeoutMillis for data.

Since
1.0

Blocks the caller for at most timeoutMillis milliseconds until the socket is readable, then performs a single-recv, best-effort read (no size preflight), returning up to n bytes. If no datagram arrives before the timeout, a SocketTimeoutException is thrown.

Implementation notes:

  • Uses a readiness wait (poll on POSIX, WSAPoll on Windows) so the per-call timeout does not alter the socket’s global receive-timeout state.
  • After readiness, delegates to the readAtMost(std::size_t) helper which enforces DatagramReceiveMode::NoPreflight (one recv) and updates the internally tracked “last remote” on unconnected sockets.
Parameters
[in]nMaximum number of bytes to return. If 0, returns an empty string.
[in]timeoutMillisTimeout in milliseconds. Must be >= 0. A value of 0 performs a non-blocking check and throws SocketTimeoutException if no data is ready.
Returns
The bytes received (size ≤ n). Marked [[nodiscard]] to avoid accidental loss.
Exceptions
SocketExceptionIf the socket is not open or an OS-level error occurs while waiting/receiving (message via SocketErrorMessage).
SocketTimeoutExceptionIf no datagram becomes available within timeoutMillis, or if the socket is non-blocking and no data is available at the moment of the call.
Precondition
The socket has been successfully created/opened. timeoutMillis ≥ 0.
Postcondition
On success, the returned string contains up to n bytes from exactly one datagram; for unconnected sockets, the internal “last remote” reflects that datagram’s sender.
Note
This is a convenience overload. For zero-allocation reads with the same timeout behavior, wait for readability externally, then call readAtMost(std::span<char>, ...).

◆ readAvailable() [1/2]

std::string DatagramSocket::readAvailable ( ) const
nodiscard

Receive the next UDP datagram and return its payload as a string, attempting to avoid truncation.

Since
1.0

Tries to return the entire next datagram:

  • First attempts a size probe (e.g., via an OS-specific query). If successful, it allocates exactly that many bytes (clamped to MaxDatagramPayloadSafe) and performs a single receive.
  • If a reliable size probe is not available, it allocates a safe maximum buffer (MaxDatagramPayloadSafe) and performs exactly one receive. In this fallback, extremely large datagrams may be truncated.

On unconnected sockets, the internally tracked “last remote” endpoint is updated to the sender. This convenience overload forces a single-recv path and does not throw on truncation in the rare fallback case (truncation is accepted and the received bytes are returned).

Blocking/timeout behavior:

  • In blocking mode, waits until a datagram arrives or a configured receive timeout elapses, then throws SocketTimeoutException.
  • In non-blocking mode with no data available, also throws SocketTimeoutException (would-block mapped).
Returns
The payload of the next datagram as a string. May be empty for a zero-length datagram.
Exceptions
SocketExceptionOn socket not open or other OS-level receive errors (message via SocketErrorMessage).
SocketTimeoutExceptionIf a receive timeout elapses before any datagram is received, or when the socket is non-blocking and no data is available.
Precondition
The socket has been successfully created/opened.
Postcondition
On success, the returned string contains the bytes received from exactly one datagram; for unconnected sockets, the internal “last remote” reflects the sender of that datagram.
Note
For strict no-truncation behavior on all platforms, prefer the span overload readAvailable(std::span<char>, const DatagramReadOptions&) and set opts.errorOnTruncate = true.
Warning
On platforms without a reliable size probe, datagrams larger than MaxDatagramPayloadSafe will be truncated in this convenience API.
Example
[[nodiscard]] std::string payload = sock.readAvailable();
// use payload
See also
readAvailable(std::span<char>, const DatagramReadOptions&) for zero-allocation reads with explicit policy.
readAtMost(std::size_t) for best-effort single-recv reads without size preflight.
read(DatagramPacket&, const DatagramReadOptions&) when you also need the sender address.

◆ readAvailable() [2/2]

std::size_t DatagramSocket::readAvailable ( std::span< char > out,
const DatagramReadOptions & opts = {} ) const

Receive the entire next UDP datagram into a caller-provided buffer, with explicit truncation policy.

Since
1.0

Attempts to copy the full datagram into out in a single receive:

  • When the platform can report the next datagram size up front, the method probes it and:
    • If opts.errorOnTruncate == true and out is smaller, it throws before reading (datagram remains queued).
    • Otherwise it performs exactly one receive sized appropriately to avoid redundant syscalls.
  • When the platform cannot preflight size, it still performs exactly one receive into out and:
    • If truncation occurs and opts.errorOnTruncate == true, it throws after the read (the tail is lost).
    • If opts.errorOnTruncate == false, it returns the truncated bytes without error.

On unconnected sockets, when opts.updateLastRemote == true, the internally tracked “last remote” endpoint is updated to the sender of this datagram.

Blocking/timeout behavior:

Parameters
[out]outDestination span that will receive up to out.size() bytes.
[in]optsRead options controlling size preflight, truncation policy, sender bookkeeping, and receive flags. Other fields are honored; this method may override the internal mode to avoid redundant preflight after a successful probe.
Returns
Number of bytes written to out. Equals the datagram size when not truncated.
Exceptions
SocketExceptionIf the socket is not open; on OS-level receive errors (message via SocketErrorMessage); or when out is too small and truncation is disallowed by opts.errorOnTruncate.
SocketTimeoutExceptionIf a receive timeout elapses before any datagram is available, or when the socket is non-blocking and no data is available.
Precondition
The socket has been successfully created/opened.
Postcondition
On success, exactly the returned number of bytes have been written to out. For unconnected sockets, when opts.updateLastRemote == true, the internal “last remote” reflects the sender.
Note
For strict no-truncation behavior across platforms, set opts.errorOnTruncate = true.
Warning
If out is smaller than the datagram and truncation is allowed, the remainder of that datagram is irretrievably dropped by the kernel per UDP semantics.
Example
std::array<char, 2048> buf{};
ro.errorOnTruncate = true; // enforce no-truncation policy
const std::size_t n = sock.readAvailable(std::span<char>(buf.data(), buf.size()), ro);
std::string_view payload(buf.data(), n);
See also
readAvailable() for the convenience string-returning overload.
readAtMost(std::span<char>, const DatagramReadOptions&) for best-effort, single-recv reads.
readInto(void*, std::size_t, const DatagramReadOptions&) for the lower-level primitive.

◆ readExact() [1/3]

DatagramReadResult DatagramSocket::readExact ( std::span< char > out,
const ReadExactOptions & opts = {} ) const
nodiscard

Span overload of readExact(...) (derives exactLen from out.size()).

Since
1.0
Parameters
[out]out[out] Destination span; on success, exactly out.size() bytes are written.
[in]opts[in] Exact-read policy and base receive options.
Returns
DatagramReadResult; see pointer overload.

◆ readExact() [2/3]

template<typename T>
DatagramReadResult jsocketpp::DatagramSocket::readExact ( T & buffer,
const std::size_t exactLen,
const ReadExactOptions & opts = {} ) const
inlinenodiscard

Receive exactly exactLen bytes from a single UDP datagram into a contiguous byte container.

Since
1.0
Template Parameters
TA contiguous byte-like container with data() and size(). Supported: dynamic (e.g., std::string, std::vector<char/unsigned char/std::byte>) and fixed-size (e.g., std::array<char/unsigned char/std::byte, N>).

Enforces exact-length semantics on top of a single datagram receive, governed by opts:

  • If a reliable size probe is available and opts.requireExact == true, the call throws before reading unless the datagram size equals exactLen. If the datagram is smaller and opts.padIfSmaller == true, the read proceeds and the tail is zero-padded after copying.
  • If size cannot be probed, one receive is performed. If the datagram is larger than exactLen and opts.requireExact == true, the call throws after the read (the kernel truncated the payload). If the datagram is smaller than exactLen and opts.padIfSmaller == true, the tail is zero-padded; otherwise the call throws due to size mismatch.
  • For dynamic containers:
    • When opts.autoResizeDynamic == true, the container is resized to exactLen up front (after validating exactLen <= MaxDatagramPayloadSafe).
    • When opts.autoResizeDynamic == false, the container must already have size() >= exactLen or the call throws. After the read, the container is shrunk or extended to exactly exactLen (new bytes are value-initialized).
  • For fixed-size containers, T::size() must be >= exactLen; the size cannot change.

Internally delegates to the pointer/span readExact(...) overload, which performs at most one kernel receive, attempts early failure via a size probe, applies zero-padding when requested, updates “last remote” per options, and returns a DatagramReadResult.

Parameters
[in,out]bufferDestination container. Must be contiguous and byte-sized.
[in]exactLenRequired logical length (> 0).
[in]optsExact-read policy (requireExact, padIfSmaller, autoResizeDynamic) and base options.
Returns
DatagramReadResult:
  • bytes Number of bytes copied from the datagram (≤ exactLen; equals exactLen when padded or exact).
  • datagramSize Full datagram size when known (0 if unknown on this platform/path).
  • truncated True if the datagram was larger than exactLen and the kernel truncated the payload.
  • src/srcLen Sender address (when available).
Exceptions
SocketExceptionIf the socket is not open; arguments are invalid; exactLen exceeds MaxDatagramPayloadSafe (when auto-resizing); the dynamic container is too small and auto-resize is disabled; OS receive errors occur (message via SocketErrorMessage); or size policy fails (e.g., requireExact mismatch).
SocketTimeoutExceptionIf a receive timeout elapses before any datagram is available, or in non-blocking mode with no data.
Precondition
Socket is open; exactLen > 0. For fixed-size containers, T::size() >= exactLen.
Postcondition
On success, buffer contains exactly exactLen bytes of payload (plus zero-padding when applicable).
Note
For strictly rejecting any truncation before reading, set opts.base.mode = DatagramReceiveMode::PreflightSize (this function will still attempt to probe when useful).
Example: dynamic buffer, auto-resize, strict exact
std::vector<char> buf;
ex.requireExact = true;
ex.padIfSmaller = false;
auto r = sock.readExact(buf, 1024, ex); // buf.size() becomes 1024 on success
Policy for enforcing an exact-byte receive on a single UDP datagram.
Definition DatagramSocket.hpp:327
bool requireExact
Controls whether the datagram size must match exactly.
Definition DatagramSocket.hpp:351
bool padIfSmaller
Controls zero-padding behavior for undersized datagrams.
Definition DatagramSocket.hpp:363
bool autoResizeDynamic
Controls automatic resizing of dynamic containers.
Definition DatagramSocket.hpp:387
Example: fixed buffer, allow padding
std::array<char, 2048> buf{};
ex.requireExact = true;
ex.padIfSmaller = true;
auto r = sock.readExact(buf, 1500, ex); // tail zero-padded up to 1500 bytes

◆ readExact() [3/3]

DatagramReadResult DatagramSocket::readExact ( void * buffer,
std::size_t exactLen,
const ReadExactOptions & opts = {} ) const
nodiscard

Receive exactly exactLen bytes from a single UDP datagram into buffer, with strict policy control.

Since
1.0

Attempts to ensure the caller ends up with exactly exactLen bytes in buffer from the next datagram:

  • If a size probe succeeds and opts.requireExact == true, the call throws before reading unless the datagram size equals exactLen. If the datagram is smaller and opts.padIfSmaller == true, the read proceeds and the tail is zero-padded after copying.
  • If a size probe is unavailable, a single receive is performed. If the datagram is larger than exactLen and opts.requireExact == true, the call throws after the read (the kernel truncated the payload). If the datagram is smaller than exactLen and opts.padIfSmaller == true, the tail is zero-padded; otherwise the call throws due to size mismatch.
  • opts.base.updateLastRemote controls whether the internally tracked “last remote” is updated.

All requests are clamped to MaxDatagramPayloadSafe. This function performs exactly one kernel receive for the payload copy (no dummy read).

Parameters
[out]buffer[out] Destination buffer receiving exactly exactLen bytes on success.
[in]exactLen[in] Required logical length. Must be > 0.
[in]opts[in] Exact-read policy (requireExact, padIfSmaller) and base receive options.
Returns
DatagramReadResult with:
  • bytes Number of bytes copied (equals min(datagramSize, exactLen)).
  • datagramSize Full datagram size when known (0 if unknown on this platform/path).
  • truncated True if the datagram was larger than exactLen and the kernel truncated the payload.
  • src/srcLen Sender address information (when available).
Exceptions
SocketExceptionIf the socket is not open, arguments are invalid, OS errors occur (message via SocketErrorMessage), or the size policy fails (e.g., mismatch with requireExact, or undersize without padIfSmaller).
SocketTimeoutExceptionIf a receive timeout elapses before any datagram is available, or in non-blocking mode with no data.
Precondition
Socket is open; buffer is non-null; exactLen > 0.
Postcondition
On success, buffer holds exactly exactLen bytes (payload plus optional zero-padding).
Note
For strictly rejecting any truncation before reading, prefer opts.base.mode = DatagramReceiveMode::PreflightSize (or leave NoPreflight; this method will still attempt to probe when useful).

◆ readFrom()

template<typename T>
DatagramReadResult jsocketpp::DatagramSocket::readFrom ( T & buffer,
std::string * senderAddr,
Port * senderPort,
const DatagramReadOptions & opts ) const
inlinenodiscard

Read one UDP datagram into a caller-provided byte container and optionally return the sender address/port.

Since
1.0
Template Parameters
TA contiguous byte container with data() and size(). Supports both dynamic (e.g., std::string, std::vector<char>) and fixed-size (e.g., std::array<char, N>) containers.

Receives exactly one datagram and copies it into buffer. If T is dynamically resizable and a reliable size probe is available, the function grows buffer up front to the exact datagram size (clamped to MaxDatagramPayloadSafe) to avoid truncation and extra copies. Truncation behavior follows opts.errorOnTruncate:

  • If a size probe succeeds and the datagram would not fit:
    • Dynamic container: the buffer is grown automatically (up to the safety cap).
    • Fixed container: if opts.errorOnTruncate == true, the function throws before reading (datagram remains queued); otherwise it will be truncated.
  • If no size probe is available, a single receive is performed. If truncation occurs and opts.errorOnTruncate == true, the function throws after the read.

When senderAddr and/or senderPort are non-null, the function resolves the numeric host and port of the datagram’s sender and writes them to the provided outputs. This works for both connected and unconnected sockets. If you only need the sender information without copying the payload into a DatagramPacket, this overload is convenient and zero-alloc for fixed buffers.

Parameters
[in,out]bufferCaller-provided destination container. For dynamic containers, it may be resized to fit the datagram. For fixed containers, its capacity limits the copy.
[out]senderAddrOptional. Receives the sender’s numeric IP string (e.g., "203.0.113.10").
[out]senderPortOptional. Receives the sender’s port.
[in]optsRead options controlling preflight, truncation policy, and bookkeeping.
Returns
DatagramReadResult with:
  • bytes — number of bytes copied into buffer,
  • datagramSize — full datagram size when known (0 if unknown on this platform/path),
  • truncatedtrue if the datagram did not fully fit in buffer,
  • src / srcLen — sender socket address (when available in the build; included in this result type).
Exceptions
SocketExceptionIf the socket is not open, OS-level receive errors occur (message via SocketErrorMessage), or truncation is disallowed by opts.errorOnTruncate and would occur.
SocketTimeoutExceptionIf a receive timeout elapses before any datagram is available, or when the socket is non-blocking and no data is available (would-block).
Precondition
The socket has been successfully created/opened.
For fixed-size containers, T::size() > 0.
Postcondition
On success, the first result.bytes elements of buffer contain the payload. If senderAddr and/or senderPort are provided, they contain the numeric sender address and port.
Note
Requests are clamped to MaxDatagramPayloadSafe. For strict no-truncation behavior across platforms, prefer opts.errorOnTruncate = true; when available, a preflight size probe avoids consuming the datagram on failure.
Example: dynamic buffer (auto-grow) and capture sender
std::vector<char> buf;
std::string fromIp;
Port fromPort{};
ro.errorOnTruncate = true;
auto r = sock.readFrom(buf, &fromIp, &fromPort, ro);
Example: fixed buffer (truncate allowed)
std::array<char, 1024> buf{};
auto r = sock.readFrom(buf, nullptr, nullptr, DatagramReadOptions{ .errorOnTruncate = false });

◆ readInto() [1/2]

DatagramReadResult DatagramSocket::readInto ( std::span< char > out,
const DatagramReadOptions & opts = {} ) const
nodiscard

Read one UDP datagram into a caller-provided span (zero allocation) with explicit truncation policy.

Since
1.0

Performs exactly one receive to copy the next datagram into out, applying the policies in opts:

  • If opts.mode != DatagramReceiveMode::NoPreflight or opts.errorOnTruncate == true, the method attempts to probe the next datagram size first. When the size is known and the span is too small and opts.errorOnTruncate == true, it throws before reading so the datagram remains queued.
  • If size cannot be probed (platform/path) or opts.mode == NoPreflight, a single receive is performed. If truncation occurs and opts.errorOnTruncate == true, it throws after the read (the tail is lost by UDP semantics). If opts.errorOnTruncate == false, the truncated bytes are returned.
  • When opts.updateLastRemote == true, the internally tracked “last remote” endpoint is updated. The request size is clamped to MaxDatagramPayloadSafe. If out.size() == 0, the function returns immediately.
Parameters
[out]outDestination span receiving up to out.size() bytes.
[in]optsRead options controlling preflight, truncation policy, and “last remote” updates.
Returns
DatagramReadResult with:
  • bytes — number of bytes copied into out,
  • datagramSize — full datagram size when known (0 if unknown on this platform/path),
  • truncatedtrue if the datagram did not fully fit in out.
Exceptions
SocketExceptionIf the socket is not open, OS-level receive errors occur (message via SocketErrorMessage), or truncation is disallowed by opts.errorOnTruncate.
SocketTimeoutExceptionIf a receive timeout elapses before any datagram is available, or when the socket is non-blocking and no data is available (would-block).
Precondition
The socket has been successfully created/opened.
Postcondition
On success, the first result.bytes elements of out contain the payload. When opts.updateLastRemote == true, the internal “last remote” reflects the sender.
Note
Prefer this overload for zero-allocation reads. For pointer-based interop with legacy APIs, use readInto(void*, std::size_t, const DatagramReadOptions&).
For strict no-truncation behavior across platforms, set opts.errorOnTruncate = true and (optionally) opts.mode = DatagramReceiveMode::PreflightSize.
Example
std::array<char, 2048> buf{};
ro.errorOnTruncate = true;
auto res = sock.readInto(std::span<char>(buf.data(), buf.size()), ro);
std::string_view payload(buf.data(), res.bytes);
See also
readInto(void*, std::size_t, const DatagramReadOptions&) for the pointer overload.
read(DatagramPacket&, const DatagramReadOptions&) when you also need the sender address.
readAvailable() for returning the entire datagram as a string.
readAtMost(std::span<char>, const DatagramReadOptions&) for best-effort single-recv reads.

◆ readInto() [2/2]

DatagramReadResult DatagramSocket::readInto ( void * buffer,
std::size_t len,
const DatagramReadOptions & opts = {} ) const
nodiscard

Read one UDP datagram into a caller-provided buffer with explicit truncation policy.

Since
1.0

Performs exactly one receive to copy the next datagram into buffer, applying the policies in opts:

  • If opts.mode != DatagramReceiveMode::NoPreflight or opts.errorOnTruncate == true, the method attempts to probe the next datagram size first. When the size is known and the buffer is too small and opts.errorOnTruncate == true, it throws before reading so the datagram remains queued.
  • If size cannot be probed (platform/path) or opts.mode == NoPreflight, a single receive is performed. If truncation occurs and opts.errorOnTruncate == true, it throws after the read (the tail is lost by UDP semantics). If opts.errorOnTruncate == false, the truncated bytes are returned.
  • When opts.updateLastRemote == true, the internally tracked “last remote” endpoint is updated from the sender address of this datagram. The request size is clamped to MaxDatagramPayloadSafe.
Parameters
[out]bufferCaller-provided destination buffer receiving up to len bytes.
[in]lenCapacity of buffer in bytes.
[in]optsRead options controlling preflight, truncation policy, and “last remote” updates.
Returns
DatagramReadResult with:
  • bytes — number of bytes copied into buffer,
  • datagramSize — full datagram size when known (0 if unknown on this platform/path),
  • truncatedtrue if the datagram did not fully fit in buffer.
Exceptions
SocketExceptionIf the socket is not open, arguments are invalid, OS-level receive errors occur (message via SocketErrorMessage), or truncation is disallowed by opts.errorOnTruncate.
SocketTimeoutExceptionIf a receive timeout elapses before any datagram is available, or when the socket is non-blocking and no data is available (would-block).
Precondition
The socket has been successfully created/opened. If buffer is non-null, len > 0.
Postcondition
On success, the first result.bytes bytes of buffer contain the payload. When opts.updateLastRemote == true, the internal “last remote” reflects the sender.
Note
Prefer the span overload for zero-allocation ergonomics: readInto(std::span<char>, const DatagramReadOptions&).
For strict no-truncation behavior across platforms, set opts.errorOnTruncate = true and (optionally) opts.mode = DatagramReceiveMode::PreflightSize.
Example
std::array<char, 2048> buf{};
ro.errorOnTruncate = true;
auto res = sock.readInto(buf.data(), buf.size(), ro);
std::string_view payload(buf.data(), res.bytes);
See also
readInto(std::span<char>, const DatagramReadOptions&) for the span overload.
read(DatagramPacket&, const DatagramReadOptions&) when you also need the sender address.
readAvailable() for returning the entire datagram as a string.
readAtMost(std::span<char>, const DatagramReadOptions&) for best-effort single-recv reads.

◆ readIntoBuffer()

std::size_t DatagramSocket::readIntoBuffer ( char * buf,
std::size_t len,
DatagramReceiveMode mode,
int recvFlags,
sockaddr_storage * outSrc,
socklen_t * outSrcLen,
std::size_t * outDatagramSz,
bool * outTruncated ) const
protected

Low-level, single-recv primitive that copies one UDP datagram into a caller buffer.

Since
1.0

Performs exactly one kernel receive. On POSIX, uses recvmsg and sets MSG_TRUNC (on Linux) to obtain precise truncation signaling; on Linux the return value with MSG_TRUNC reflects the full datagram size even when the buffer is smaller. When a size preflight is requested via mode, the next datagram size is queried (if supported) and the requested copy length is clamped accordingly. This function is policy-free: it never throws solely because truncation happened; instead it reports size and truncation through outDatagramSz and outTruncated so higher-level APIs can decide.

Parameters
[in,out]bufDestination buffer receiving up to len bytes.
[in]lenCapacity of buf in bytes; the function never writes more than this.
[in]modeReceive mode. If not DatagramReceiveMode::NoPreflight, a size probe is attempted to refine the requested copy length.
[in]recvFlagsFlags passed to the underlying receive. May be OR’ed with platform flags internally (e.g., MSG_TRUNC on Linux).
[out]outSrcOptional. Sender address as returned by the kernel.
[in,out]outSrcLenOptional. On input, capacity of outSrc. On output, actual size written.
[out]outDatagramSzOptional. Full datagram size when known (preflight or Linux+MSG_TRUNC); otherwise set to the copied byte count (best effort).
[out]outTruncatedOptional. Set to true if the datagram did not fully fit in buf.
Returns
Number of bytes actually written to buf (≤ len). May be 0 for a zero-length datagram.
Exceptions
SocketExceptionOn invalid arguments, socket not open, or other OS-level errors (message via SocketErrorMessage).
SocketTimeoutExceptionIf a configured receive timeout elapses before any datagram is received, or when the socket is non-blocking and no data is available (would-block).
Precondition
The socket handle is valid (open). If outSrc is non-null, outSrcLen points to a writable size.
Postcondition
On success, exactly the returned number of bytes are stored in buf. When provided, outSrc/outSrcLen reflect the sender; outDatagramSz and outTruncated report size and truncation status.
Note
The requested copy length is always clamped to MaxDatagramPayloadSafe for safety.
Warning
On platforms without a reliable size probe and without MSG_TRUNC semantics, truncation detection may be heuristic (e.g., a full buffer implies possible truncation).
Example
std::array<char, 2048> buf{};
sockaddr_storage src{};
socklen_t srcLen = sizeof(src);
std::size_t pktSize = 0;
bool wasTrunc = false;
const std::size_t n = sock.readIntoBuffer(buf.data(), buf.size(),
0, &src, &srcLen, &pktSize, &wasTrunc);
// n bytes are in buf; pktSize is the full size when known; wasTrunc indicates truncation.

◆ readIntoExact()

std::size_t DatagramSocket::readIntoExact ( void * buffer,
std::size_t len ) const

Strict exact-length UDP receive into a caller-provided buffer (single datagram).

Since
1.0

Copies the next datagram into buffer and enforces that the datagram size matches len exactly. The method prefers an early, non-destructive failure: it attempts to probe the next datagram size first and throws before reading if the size is not exactly len. If a probe is not available on the platform, it performs one receive and throws afterward if the payload was truncated or shorter than len.

Behavior is equivalent to calling readExact(buffer, len, ReadExactOptions{ .requireExact = true, .padIfSmaller = false, .base.mode = DatagramReceiveMode::PreflightSize }). A single kernel receive is used for the payload copy; no allocation occurs.

Parameters
[out]buffer[out] Destination buffer that must have capacity for exactly len bytes.
[in]len[in] Required length in bytes; the datagram must be exactly this size.
Returns
Number of bytes written to buffer. On success this equals len.
Exceptions
SocketExceptionIf the socket is not open; arguments are invalid; OS-level receive errors occur (message via SocketErrorMessage); or the datagram size does not equal len.
SocketTimeoutExceptionIf a configured receive timeout elapses before any datagram is available, or when the socket is non-blocking and no data is available (would-block).
Precondition
The socket has been successfully created/opened. buffer is non-null. len > 0.
Postcondition
On success, exactly len bytes have been written to buffer and the datagram queue advanced by one. On unconnected sockets, the internal “last remote” reflects the sender.
Note
For variable-length reads or padding behavior, use the more general readExact(void*, std::size_t, const ReadExactOptions&) overload.
Warning
If the platform cannot preflight size, an oversized datagram will be consumed by the kernel and this function will throw after the read; the excess bytes are lost per UDP semantics.
Example
std::array<char, 512> buf{};
// Expect exactly 512 bytes in the next datagram; throw otherwise.
const std::size_t n = sock.readIntoExact(buf.data(), buf.size());
// n == 512 on success

◆ readPrefixed()

template<typename T, std::enable_if_t< std::is_integral_v< T > &&std::is_unsigned_v< T > &&std::is_trivially_copyable_v< T >, int > = 0>
std::string jsocketpp::DatagramSocket::readPrefixed ( std::size_t maxPayloadLen = MaxDatagramPayloadSafe,
const std::endian prefixEndian = std::endian::big ) const
inlinenodiscard

Read a length-prefixed UDP datagram and return the payload (prefix type T).

Since
1.0
Template Parameters
TUnsigned, trivially copyable integer type used for the length prefix (e.g., uint16_t, uint32_t, uint64_t).

Expects the next datagram’s payload to begin with a T-sized length field followed by exactly that many payload bytes. The prefix is interpreted in the specified byte order and validated against the actual datagram size. The function:

  • Reads the entire datagram (throws on truncation) using a single receive.
  • Verifies that the datagram size is at least sizeof(T) and that the prefix equals the remaining payload length.
  • Enforces maxPayloadLen to guard against oversized frames.

Works for connected and unconnected sockets; on unconnected sockets the internally tracked “last remote” endpoint is updated to the sender.

Parameters
[in]maxPayloadLenMaximum allowed payload length (not counting the prefix). Clamped to MaxDatagramPayloadSafe. Use to prevent pathological allocations. Defaults to MaxDatagramPayloadSafe.
[in]prefixEndianByte order of the length prefix. Defaults to big-endian.
Returns
The decoded payload bytes as a std::string. Marked [[nodiscard]].
Exceptions
SocketExceptionIf the socket is not open; the datagram is smaller than sizeof(T); the prefix/payload sizes mismatch; the payload exceeds maxPayloadLen; or on OS-level receive errors (message via SocketErrorMessage).
SocketTimeoutExceptionIf a receive timeout elapses before any datagram is available, or when the socket is non-blocking and no data is available (would-block).
Precondition
The socket has been successfully created/opened.
Postcondition
On success, the returned string contains exactly the bytes declared by the prefix.
Note
This function throws rather than silently truncating. If you want best-effort reads, use readAtMost(...) instead.
Example
// Datagram format: [u32_be length][payload...]
std::string payload = sock.readPrefixed<std::uint32_t>();

◆ readv()

DatagramReadResult DatagramSocket::readv ( std::span< BufferView > buffers,
const DatagramReadOptions & opts = {} ) const
nodiscard

Scatter-gather receive: read one UDP datagram into multiple non-contiguous buffers.

Since
1.0

Copies the next datagram across the spans in buffers using a single kernel receive:

  • Computes total capacity = sum of buffer sizes (clamped to MaxDatagramPayloadSafe).
  • If size preflight succeeds and opts.errorOnTruncate == true, throws before reading when the datagram would not fit. Otherwise performs exactly one receive and reports truncation.
  • On POSIX, uses recvmsg with iovec[] (Linux adds MSG_TRUNC to learn the full size even when truncated). On Windows, uses WSARecvFrom with WSABUF[].
  • On unconnected sockets, when opts.updateLastRemote == true, updates the internally tracked “last remote” to the sender of this datagram.
Parameters
[in,out]buffersScatter list of writable buffers; each entry must have a valid pointer when its size > 0.
[in]optsRead options controlling preflight, truncation policy, sender bookkeeping, and flags.
Returns
DatagramReadResult { bytes, datagramSize, truncated, src, srcLen }.
Exceptions
SocketExceptionIf the socket is not open; buffer arguments are invalid; OS-level errors occur (message via SocketErrorMessage); or truncation is disallowed by opts.errorOnTruncate.
SocketTimeoutExceptionIf a receive timeout elapses before any datagram is available, or when the socket is non-blocking and no data is available (would-block).
Precondition
The socket has been successfully created/opened.
Postcondition
On success, the first result.bytes bytes have been written across the buffers in order. For unconnected sockets, when opts.updateLastRemote == true, the internal “last remote” reflects the sender.
Note
This method never allocates payload storage; it only references your buffers. For single-buffer cases, prefer readInto(std::span<char>, ...).

◆ readvAll()

DatagramReadResult DatagramSocket::readvAll ( std::span< BufferView > buffers,
const DatagramReadOptions & opts = {} ) const
nodiscard

Scatter-gather receive that guarantees the entire next datagram fits the provided buffers.

Since
1.0

Performs exactly one kernel receive to copy the full datagram across buffers in order. If the datagram would not fit in the aggregate capacity, the call fails before reading when a size probe is available; otherwise, it performs one receive and fails after the read if truncation occurred. This is a strict, no-truncation variant of readv(...).

On unconnected sockets, when opts.updateLastRemote == true, the internally tracked “last remote” endpoint is updated to the sender of this datagram.

Parameters
[in,out]buffersScatter list of writable buffers. Each view must have a valid pointer when its size > 0.
[in]optsRead options. This method forces errorOnTruncate = true and prefers a size preflight (mode = PreflightSize when the caller left it as NoPreflight).
Returns
DatagramReadResult with:
  • bytes Number of bytes copied across buffers (equals the datagram size on success),
  • datagramSize Full datagram size when known (0 if unknown on this platform/path),
  • truncated Always false on success (method throws on truncation),
  • src/srcLen Sender address information.
Exceptions
SocketExceptionIf the socket is not open; buffer arguments are invalid; OS-level errors occur (message via SocketErrorMessage); or the datagram does not fit the provided capacity.
SocketTimeoutExceptionIf a receive timeout elapses before any datagram is available, or when the socket is non-blocking and no data is available (would-block).
Precondition
The socket has been successfully created/opened.
Postcondition
On success, the entire datagram has been written across buffers and removed from the queue.
Note
This function never allocates payload storage. If you need automatic resizing, use a dynamic container API (e.g., read(std::string&) or readExact with autoResizeDynamic).
Example
std::array<char, 8> hdr{};
std::array<char, 64> body{};
BufferView views[] = {
{hdr.data(), hdr.size()},
{body.data(), body.size()}
};
DatagramReadOptions ro{};
auto r = sock.readvAll(std::span<BufferView>(views, 2), ro); // throws if datagram > 72 bytes

◆ readvAllBytes()

std::size_t jsocketpp::DatagramSocket::readvAllBytes ( std::span< BufferView > buffers,
const DatagramReadOptions & opts = {} ) const
inline

Back-compat convenience returning only the number of bytes copied.

Since
1.0
Parameters
[in,out]buffersSee readvAll(std::span<BufferView>, const DatagramReadOptions&) const
[in]optsSee readvAll(std::span<BufferView>, const DatagramReadOptions&) const
Returns
Bytes copied (equals the datagram size on success).

◆ readvAllWithTotalTimeout()

DatagramReadResult DatagramSocket::readvAllWithTotalTimeout ( std::span< BufferView > buffers,
int totalTimeoutMillis,
const DatagramReadOptions & opts = {} ) const
nodiscard

Scatter-gather, strict no-truncation receive with a per-call total timeout.

Since
1.0

Waits up to totalTimeoutMillis milliseconds for the socket to become readable, then performs a single scatter-gather receive that must copy the entire next datagram into buffers. If the datagram would not fit in the aggregate capacity, the call fails (either before reading when a size probe is available, or after the read if not). This is a timed variant of readvAll(...).

The readiness wait uses poll/WSAPoll via hasPendingData(...), so this per-call timeout does not modify the socket’s global receive timeout. On unconnected sockets, when opts.updateLastRemote == true, the internally tracked “last remote” endpoint is updated to the sender of this datagram.

Parameters
[in,out]buffersScatter list of writable buffers. Each view must have a valid pointer when its size > 0.
[in]totalTimeoutMillisTotal timeout in milliseconds (>= 0). 0 performs a non-blocking readiness check.
[in]optsRead options. This method enforces strict no-truncation by setting errorOnTruncate = true and preferring a size preflight (mode = PreflightSize when left as NoPreflight). Other fields are honored.
Returns
DatagramReadResult with:
  • bytes Number of bytes copied (equals the datagram size on success),
  • datagramSize Full datagram size when known (0 if unknown on this platform/path),
  • truncated Always false on success (the method throws on truncation),
  • src/srcLen Sender address information.
Exceptions
SocketExceptionIf the socket is not open; buffer arguments are invalid; OS-level errors occur (message via SocketErrorMessage); or the datagram does not fit the provided capacity.
SocketTimeoutExceptionIf no datagram becomes ready within totalTimeoutMillis, or when the socket is non-blocking and no data is available.
Precondition
The socket has been successfully created/opened. totalTimeoutMillis >= 0.
Postcondition
On success, the entire datagram has been written across buffers and removed from the queue. For unconnected sockets, when opts.updateLastRemote == true, the internal “last remote” reflects the sender.
Note
If you don’t need a timeout, use readvAll(...). If best-effort truncation is acceptable, see readvAtMostWithTimeout(...).
Example
std::array<char, 8> hdr{};
std::array<char, 64> body{};
BufferView views[] = {
{hdr.data(), hdr.size()},
{body.data(), body.size()}
};
DatagramReadOptions ro{};
auto r = sock.readvAllWithTotalTimeout(std::span<BufferView>(views, 2), 2500, ro);

◆ readvAllWithTotalTimeoutBytes()

std::size_t jsocketpp::DatagramSocket::readvAllWithTotalTimeoutBytes ( std::span< BufferView > buffers,
int totalTimeoutMillis,
const DatagramReadOptions & opts = {} ) const
inline

Convenience wrapper returning only the number of bytes copied.

Since
1.0

◆ readvAtMostWithTimeout() [1/2]

std::size_t jsocketpp::DatagramSocket::readvAtMostWithTimeout ( std::span< BufferView > buffers,
int timeoutMillis ) const
inline

Convenience wrapper returning only the number of bytes read.

Since
1.0

◆ readvAtMostWithTimeout() [2/2]

DatagramReadResult DatagramSocket::readvAtMostWithTimeout ( std::span< BufferView > buffers,
int timeoutMillis,
const DatagramReadOptions & opts = {} ) const
nodiscard

Scatter-gather, best-effort read of the next datagram with a per-call timeout.

Since
1.0

Waits up to timeoutMillis milliseconds for the socket to become readable, then performs a single-recv, at-most scatter-gather read into buffers:

  • Copies up to the aggregate capacity of buffers (clamped by MaxDatagramPayloadSafe).
  • If the datagram is larger than the aggregate capacity, the excess is discarded (standard UDP truncation).
  • No size preflight is performed; truncation is accepted (no exception) to preserve best-effort semantics.

On unconnected sockets, when opts.updateLastRemote == true, the internally tracked “last remote” endpoint is updated to the sender of this datagram.

Parameters
[in,out]buffersScatter list of writable buffers; each entry must have a valid pointer if its size > 0.
[in]timeoutMillisTimeout in milliseconds (>= 0). 0 means non-blocking readiness check.
[in]optsRead options; fields other than mode and errorOnTruncate are honored. This method forces mode = DatagramReceiveMode::NoPreflight and errorOnTruncate = false to ensure single-recv, best-effort behavior.
Returns
DatagramReadResult { bytes, datagramSize (best effort), truncated, src, srcLen }.
Exceptions
SocketExceptionIf the socket is not open; buffer arguments are invalid; or an OS-level error occurs (message via SocketErrorMessage).
SocketTimeoutExceptionIf no datagram becomes ready within timeoutMillis, or when the socket is non-blocking and no data is available (would-block).
Precondition
The socket has been successfully created/opened. timeoutMillis >= 0.
Postcondition
On success, up to the aggregate buffer capacity has been written across buffers.
Note
For strict no-truncation scatter-gather reads, use readvAll.

◆ resolveIPv4()

in_addr MulticastSocket::resolveIPv4 ( std::string_view host)
staticprotected

Resolve a host string to an IPv4 address (in_addr, network byte order).

Converts host into an IPv4 address suitable for socket APIs. Resolution strategy:

  1. Fast path: if host is an IPv4 literal (e.g., "239.1.2.3"), parse it with inet_pton(AF_INET, ...) without any name-service lookup.
  2. Fallback: otherwise, call the project helper resolveAddress(host, Port{0}, AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0) and extract the first AF_INET result.

The returned in_addr is in network byte order, ready for setsockopt, sendto, and multicast membership structures.

Parameters
[in]hostHost string to resolve. Accepts IPv4 literals ("A.B.C.D") or names/hostnames resolvable by the system’s name services. Must not be empty.
Returns
Resolved IPv4 address in network byte order.
Precondition
  • host is not empty.
Postcondition
  • No persistent side effects; this function does not modify socket state.
Exceptions
SocketException
  • If host is empty.
  • If resolution succeeds but yields no AF_INET address.
  • If name resolution fails; the exception carries the OS or getaddrinfo error code and a descriptive message from SocketErrorMessage(..., true).
Note
  • CIDR notation and interface suffixes are not supported; pass a single host literal or resolvable name.
  • If a name resolves to multiple IPv4 addresses, the first result from resolveAddress is used.
  • Use this helper before joining IPv4 multicast groups to ensure a correct address family and byte order.
Related
// Parse a literal IPv4 multicast group
in_addr g = resolveIPv4("239.1.2.3");
throw SocketException("Expected an IPv4 multicast address");
}
// Resolve a hostname and join on the default interface
in_addr g2 = resolveIPv4("mcast.example.com");
in_addr any{};
any.s_addr = htonl(INADDR_ANY);
joinGroupIPv4(g2, any);
// Resolve an interface IPv4 address (egress) by literal
in_addr eg = resolveIPv4("192.0.2.10");
Represents socket-related errors in the jsocketpp library.
Definition SocketException.hpp:63
static bool is_ipv4_multicast(const in_addr v4)
Test whether an IPv4 address is in the multicast range (224.0.0.0/4).
Definition SocketOptions.hpp:2370
void joinGroupIPv4(in_addr group, in_addr iface)
Join an IPv4 any-source multicast (ASM) group on a specific interface.
Definition SocketOptions.cpp:470
static in_addr resolveIPv4(std::string_view host)
Resolve a host string to an IPv4 address (in_addr, network byte order).
Definition MulticastSocket.cpp:94

◆ resolveIPv6()

in6_addr MulticastSocket::resolveIPv6 ( std::string_view host)
staticprotected

Resolve a host string to an IPv6 address (in6_addr).

Converts host into an IPv6 address suitable for socket APIs. Resolution strategy:

  1. Fast path: if host is an IPv6 literal (e.g., "ff02::1"), parse it with inet_pton(AF_INET6, ...) and avoid any name-service lookup.
  2. Fallback: otherwise, call the project helper resolveAddress(host, Port{0}, AF_INET6, SOCK_DGRAM, IPPROTO_UDP, 0) and extract the first AF_INET6 result.

The returned in6_addr is in the canonical struct form expected by socket calls, multicast membership records, and IPv6 setsockopt options.

Parameters
[in]hostHost string to resolve. Accepts IPv6 literals (e.g., "ff02::1", "2001:db8::1") or names/hostnames resolvable by the system’s name services. Must not be empty.
Returns
Resolved IPv6 address.
Precondition
  • host is not empty.
Postcondition
  • No persistent side effects; this function does not modify socket state.
Exceptions
SocketException
  • If host is empty.
  • If resolution succeeds but yields no AF_INET6 address.
  • If name resolution fails; the exception carries the OS or getaddrinfo error code and a descriptive message from SocketErrorMessage(..., true).
Note
  • Zone identifiers such as "ff02::1%eth0" are not interpreted here. Supply the interface index separately where required (e.g., for multicast membership or egress selection).
  • If a name resolves to multiple IPv6 addresses, the first result from resolveAddress is used.
Related
// Parse a literal IPv6 multicast group and join on interface index 0 (default)
in6_addr g6 = resolveIPv6("ff02::1:3");
if (!is_ipv6_multicast(g6)) {
throw SocketException("Expected an IPv6 multicast address");
}
joinGroupIPv6(g6, 0); // 0 = default interface
// Resolve a hostname and join on a specific interface index
unsigned int ifidx = 12; // e.g., result of if_nametoindex("eth0") on POSIX
in6_addr g6host = resolveIPv6("mcast6.example.com");
joinGroupIPv6(g6host, ifidx);
static bool is_ipv6_multicast(const in6_addr &v6)
Test whether an IPv6 address is in the multicast range (ff00::/8).
Definition SocketOptions.hpp:2430
void joinGroupIPv6(in6_addr group, unsigned int ifindex)
Join an IPv6 any-source multicast (ASM) group on a specific interface index.
Definition SocketOptions.cpp:500
static in6_addr resolveIPv6(std::string_view host)
Resolve a host string to an IPv6 address (in6_addr).
Definition MulticastSocket.cpp:124

◆ sendPrefixedConnected()

template<typename T>
void jsocketpp::DatagramSocket::sendPrefixedConnected ( const std::span< const std::byte > payload) const
inlineprotected

Build and send a length-prefixed UDP datagram to the connected peer (no pre-wait).

Template Parameters
TUnsigned integral type used for the length prefix (e.g., std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t). A compile-time check enforces that T is an unsigned integral.

Constructs a single datagram with layout [ prefix(T, big-endian) | payload ] where the prefix encodes payload.size() in network byte order. The method: 1) verifies the socket is open and connected; 2) encodes the prefix via encodeLengthPrefixBE<T>(payload.size()); 3) computes total = sizeof(T) + payload.size() and enforces the connected peer’s protocol maxima via enforceSendCapConnected(total) (prevents guaranteed EMSGSIZE); 4) coalesces [prefix|payload] into one contiguous buffer and performs one send.

This function does not poll for writability. On non-blocking sockets, if the send buffer is temporarily full, the underlying send may fail (e.g., EWOULDBLOCK / WSAEWOULDBLOCK) and will be surfaced as a SocketException. For blocking behavior, prefer writeAll() or writeWithTimeout().

Atomicity: UDP is message-oriented; on success, the entire [prefix|payload] frame is sent in a single datagram. On exception, no bytes are considered transmitted.

Zero-length payloads are valid: a datagram containing only the prefix is sent.

Parameters
[in]payloadBinary bytes to append after the length prefix (may be empty).
Precondition
getSocketFd() != INVALID_SOCKET
isConnected() == true
Postcondition
On success, exactly sizeof(T) + payload.size() bytes are handed to the kernel as one UDP datagram. Socket state and options are unchanged.
Exceptions
SocketException
  • Logical (error code = 0):
  • System (OS error + SocketErrorMessage(...)):
    • Send failures such as EWOULDBLOCK, ENOBUFS, ENETUNREACH, EHOSTUNREACH, etc.
Since
1.0
See also
writePrefixed<T>(std::string_view), writePrefixed<T>(std::span<const std::byte>), writeWithTimeout(std::string_view, int), writeAll(std::string_view), encodeLengthPrefixBE<T>(std::size_t), enforceSendCapConnected(std::size_t)
// Example: send a length-prefixed frame with a 16-bit prefix
std::string_view text = "hello";
sock.sendPrefixedConnected<std::uint16_t>(DatagramSocket::asBytes(text));

◆ sendPrefixedUnconnected()

template<typename T>
void jsocketpp::DatagramSocket::sendPrefixedUnconnected ( const std::string_view host,
const Port port,
const std::span< const std::byte > payload )
inlineprotected

Build and send a length-prefixed UDP datagram to (host, port) on the unconnected path.

Template Parameters
TUnsigned integral type for the length prefix (e.g., std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t). A compile-time check enforces that T is unsigned integral.

Constructs a single frame [ prefix(T, big-endian) | payload ], where the prefix encodes payload.size() in network byte order, then transmits it to the specified destination using sendUnconnectedTo(). That helper resolves A/AAAA records, skips address families whose theoretical UDP maximum cannot carry the frame, attempts a single send to the first compatible candidate, and caches the last destination (without marking the socket connected).

Processing steps: 1) Verify socket is open. 2) Encode prefix via encodeLengthPrefixBE<T>(payload.size()) (validates that size fits in T). 3) Coalesce [prefix|payload] once and dispatch through sendUnconnectedTo(host, port, ...).

Zero-length payloads are valid: a datagram containing only the prefix is sent.

Atomicity: UDP is message-oriented; on success the entire [prefix|payload] frame is sent in one datagram. On exception, no bytes are considered transmitted.

Parameters
[in]hostDestination hostname or numeric address (IPv4/IPv6).
[in]portDestination UDP port (> 0).
[in]payloadBinary bytes to append after the length prefix (may be empty).
Precondition
getSocketFd() != INVALID_SOCKET
Postcondition
On success, exactly sizeof(T) + payload.size() bytes are handed to the kernel as one datagram.
Exceptions
SocketException
  • Logical (error code = 0):
  • System (OS error + SocketErrorMessage(...)):
    • Resolution or send failures reported by the OS (e.g., ENETUNREACH, EHOSTUNREACH, ENOBUFS).
Note
Family-specific size enforcement (IPv4 vs IPv6) and destination caching are handled inside sendUnconnectedTo(). This method does not pre-wait for writability; if you need blocking behavior, perform an explicit readiness wait on a connected socket or design a higher-level retry.
Since
1.0
See also
writePrefixedTo<T>(std::string_view, Port, std::string_view), writePrefixed<T>(std::span<const std::byte>), encodeLengthPrefixBE<T>(std::size_t), sendUnconnectedTo(std::string_view, Port, const void*, std::size_t), MaxUdpPayloadIPv4, MaxUdpPayloadIPv6
// Example: send a length-prefixed binary frame to a host/port using a 16-bit prefix.
std::array<std::byte, 3> data{std::byte{0xDE}, std::byte{0xAD}, std::byte{0xBE}};
sock.sendPrefixedUnconnected<std::uint16_t>("239.0.0.1", 5000, std::span<const std::byte>{data});

◆ sendUnconnectedTo()

void DatagramSocket::sendUnconnectedTo ( std::string_view host,
Port port,
const void * data,
std::size_t len )
protected

Resolve and send one unconnected UDP datagram to the first compatible destination.

Resolves host and port (AF_UNSPEC, UDP), iterates all A/AAAA candidates, and:

  • Skips any family whose theoretical UDP maximum would be exceeded by len (MaxUdpPayloadIPv4/MaxUdpPayloadIPv6).
  • Sends the datagram with a single syscall (internal::sendExactTo) to the first compatible candidate that succeeds.
  • On success, remembers the last remote endpoint for helpers (without flipping the socket into a connected state).

If no candidates can even be attempted (e.g., payload > IPv6 max or only A records for a payload that requires IPv6), throws a logical SocketException with a clear diagnostic. If at least one attempt is made and all fail, throws a SocketException with the last OS error (GetSocketError()/SocketErrorMessage()).

This helper is intended for all unconnected write paths (e.g., writeTo(...), write(const DatagramPacket&) when the packet specifies a destination).

Parameters
[in]hostDestination hostname or numeric address (IPv4/IPv6).
[in]portDestination UDP port (> 0).
[in]dataPointer to payload (may be null iff len == 0).
[in]lenNumber of bytes to send in a single UDP datagram.
Precondition
getSocketFd() != INVALID_SOCKET
Exceptions
SocketException
  • With code 0 and an explanatory message if no address family can carry the payload.
  • With the last OS error code/message if all attempted sends fail.
Note
Zero-length datagrams are valid; this helper returns 0 without sending.
See also
writeTo(), write(const DatagramPacket&), MaxUdpPayloadIPv4, MaxUdpPayloadIPv6

◆ setInternalBufferSize()

void DatagramSocket::setInternalBufferSize ( std::size_t newLen)

Sets the size of the internal buffer used for string-based UDP receive operations.

This method controls the size of the internal buffer used internally by read<std::string>(). It does not affect the operating system's socket-level receive buffer (SO_RCVBUF), nor does it apply to fixed-size read<T>() calls.


🧠 Purpose

  • Limits the maximum number of bytes read<std::string>() can receive in a single call
  • Controls the size of the internally managed std::vector<char> buffer
  • Affects only high-level string reads from connected UDP sockets

⚙️ Implementation Details

  • Resizes an internal std::vector<char> used exclusively by read<std::string>()
  • Does not impact read<T>() or receiveFrom() which use their own fixed-size buffers
  • Thread-safe with respect to other DatagramSocket instances
  • Safe to call at any time after construction

🧪 Example

DatagramSocket udp(12345);
udp.setInternalBufferSize(8192); // set 8 KB for string reads
udp.connect("192.168.1.100", 12345);
std::string message = udp.read<std::string>();

Parameters
[in]newLenNew size (in bytes) for the internal buffer
Exceptions
std::bad_allocIf resizing the buffer fails due to memory allocation
See also
read<std::string>() Uses this buffer for connected-mode string reads
receiveFrom() Uses its own internal buffer, not affected by this setting
setReceiveBufferSize() Sets the OS-level socket buffer
setSendBufferSize() For tuning datagram send capacity

◆ setLoopbackMode()

void MulticastSocket::setLoopbackMode ( bool enable)

Enable or disable multicast loopback for this socket.

Controls whether multicast datagrams sent by this socket may be delivered back to the local host (i.e., whether the sender can observe its own multicast transmissions). This affects local delivery only — it does not change what remote receivers get.

  • Enabled (true): the kernel may deliver local copies of outbound multicast to sockets on the same host that have joined the destination group, including this socket if it has joined.
  • Disabled (false): local delivery of this socket’s own multicast traffic is suppressed; other hosts on the network are unaffected.

This setting is per-socket and applies to multicast only. It does not affect unicast traffic.

Parameters
[in]enableSet true to allow local delivery of this socket’s multicast transmissions, or false to suppress local delivery.
Precondition
  • The underlying descriptor is a valid UDP-capable socket (AF_INET or AF_INET6).
Postcondition
  • The socket’s multicast loopback policy is updated. Future multicast sends from this socket follow the new policy; in-flight packets are unaffected.
Platform mapping
  • IPv4: setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &flag, sizeof(flag))
  • IPv6: setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &flag, sizeof(flag))
Error conditions
  • The socket is invalid or closed.
  • The socket family cannot be determined or is unsupported on this platform.
  • The underlying setsockopt call fails, e.g., ENOTSOCK, EINVAL, ENOPROTOOPT (Windows: WSAENOTSOCK, WSAEINVAL, WSAENOPROTOOPT).
Exceptions
SocketExceptionIf the option cannot be applied. The exception carries the OS error code and a descriptive message produced by SocketErrorMessage(...).
Note
  • To actually receive your own multicast transmissions on this socket, two conditions must hold: (1) loopback is enabled here, and (2) the socket has joined the destination group.
  • Typical default is enabled on many stacks, but this is implementation-defined. Use getTimeToLive() / getMulticastTTL() and getMulticastLoopback() to confirm defaults in your environment.
Related options
// Suppress receiving our own announcements on this host
sock.setMulticastInterface("eth0");
sock.joinGroup("239.1.2.3");
sock.setLoopbackMode(false); // do not receive our own packets locally
void joinGroup(const std::string &groupAddr, const std::string &iface)
Join a multicast group on an optional interface (string-friendly).
Definition MulticastSocket.cpp:173
void setLoopbackMode(bool enable)
Enable or disable multicast loopback for this socket.
Definition MulticastSocket.cpp:79

◆ setMulticastInterface()

void MulticastSocket::setMulticastInterface ( const std::string & iface)

Select the default outgoing interface for multicast transmissions.

Sets the per-socket egress interface that will be used for subsequent multicast sends. This is a convenience wrapper that accepts human-friendly identifiers and delegates to the per-family setters.

Accepted forms for iface

  • Empty string: reset the egress to the system default for this socket’s family only (IPv4: INADDR_ANY; IPv6: index 0). The family is determined via detectFamily(_sockFd), so a single-family socket will not attempt to set options for the other family.
  • IPv4 literal (e.g., "192.0.2.10"): choose that address as the IPv4 multicast egress; maps to IP_MULTICAST_IF.
  • IPv6 interface identifier:
    • Decimal interface index string (e.g., "12") on any platform.
    • POSIX only: an interface name (e.g., "eth0"), resolved with if_nametoindex(). These map to IPV6_MULTICAST_IF. On Windows, names are not supported; supply a numeric index string instead.

Behavior

  • If iface is empty, the method resets the egress only for the socket’s actual family (IPv4 or IPv6) and clears the cached _currentInterface.
  • If iface parses as an IPv4 literal, the IPv4 egress is set and the cache is updated to the provided string.
  • Otherwise, iface is interpreted as an IPv6 identifier and converted to an index using toIfIndexFromString(iface); the IPv6 egress is set and the cache is updated to the provided string.
  • The cached _currentInterface is updated only after the OS call succeeds.

Notes

  • This method does not join or leave multicast groups; it affects only where outbound multicast is sent. Use the join/leave APIs to control what the socket receives.
  • For link-local IPv6 destinations, using a correct interface index is often mandatory; prefer a non-empty IPv6 identifier in those cases.
Parameters
[in]ifaceInterface selector as described above. Pass "" to reset to the per-family system default.
Exceptions
SocketException
  • The socket family cannot be determined or is unsupported.
  • iface is malformed or unsupported on the current platform (e.g., an interface name on Windows for IPv6).
  • The underlying setsockopt call fails (IP_MULTICAST_IF for IPv4, IPV6_MULTICAST_IF for IPv6). The exception includes an OS error code and a descriptive message.
Related
// Reset to system default for this socket's family
// Choose a specific IPv4 egress address
sock.setMulticastInterface("192.0.2.10");
// Choose IPv6 egress by numeric index (any platform)
// POSIX: choose IPv6 egress by interface name
sock.setMulticastInterface("eth0");

◆ setTimeToLive()

void MulticastSocket::setTimeToLive ( int ttl)

Set the time-to-live (TTL) / hop limit for outgoing multicast packets.

Sets this socket’s default multicast scope for subsequent transmissions:

  • IPv4: applies to IP_MULTICAST_TTL (time-to-live).
  • IPv6: applies to IPV6_MULTICAST_HOPS (hop limit).

The value constrains how far outbound multicast packets may propagate:

  • 0 — restricted to the local host (no egress onto the network);
  • 1 — restricted to the local link/subnet (commonly the default);
  • higher values — permit traversal across additional multicast routers up to the limit (e.g., 32 ~ site, 64 ~ region, 128 ~ continent, 255 ~ unrestricted).

This setting is per-socket and affects multicast only. Unicast scope is controlled independently via IP_TTL / IPV6_UNICAST_HOPS. Per-message control data (e.g., IP_MULTICAST_TTL or IPV6_HOPLIMIT with sendmsg) can override this default for individual packets.

Parameters
[in]ttlHop limit (IPv6) or TTL (IPv4), in the range [0, 255].
Precondition
  • The underlying descriptor is a valid socket for AF_INET or AF_INET6 (typically UDP).
Postcondition
  • The socket’s default multicast TTL/hop limit is updated. Future multicast sends from this socket use the new value unless overridden per message.
Platform mapping
  • IPv4: setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &v, sizeof(v))
  • IPv6: setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &v, sizeof(v))
Error conditions
  • ttl is outside [0, 255].
  • The socket is invalid or closed.
  • The socket family cannot be determined or is unsupported.
  • The underlying setsockopt call fails (e.g., ENOTSOCK, EINVAL, ENOPROTOOPT; Windows equivalents: WSAENOTSOCK, WSAEINVAL, WSAENOPROTOOPT).
Exceptions
SocketExceptionIf validation fails or the operating system rejects the option. The exception includes the OS error code and a descriptive message from SocketErrorMessage(...).
Note
  • Typical initial values are implementation-defined (often 1); set an explicit value during initialization for deterministic behavior.
  • If other threads call this function concurrently with sends, packets already queued by the kernel may still carry the previous TTL/hop limit.
Related options
// Limit announcements to the local link
sock.setMulticastInterface("eth0"); // choose an egress (POSIX name or index string)
sock.setTimeToLive(1); // link-local only
// Widen scope later (e.g., site level)
sock.setTimeToLive(32);
// Confirm current default
int ttl = sock.getMulticastTTL();
int getMulticastTTL() const
Get the socket’s default multicast hop limit / TTL.
Definition SocketOptions.cpp:415
void setTimeToLive(int ttl)
Set the time-to-live (TTL) / hop limit for outgoing multicast packets.
Definition MulticastSocket.cpp:69

◆ throwSizeMismatch()

void jsocketpp::DatagramSocket::throwSizeMismatch ( const std::size_t expected,
const std::size_t actual,
const bool isProbedKnown )
inlinestaticprotected

Throw a descriptive exception when a UDP datagram’s size differs from what was expected.

Emits a uniform, user-friendly error when the size of the next datagram does not match the caller’s expectation. This is typically used after either:

  • A size probe (e.g., via FIONREAD or MSG_PEEK|MSG_TRUNC) indicated an expected size, or
  • The caller required an exact payload size (e.g., fixed-size read into a POD object).

The exception message intentionally distinguishes whether the actual value came from a prior probe versus a receive operation, to aid debugging (reordering, truncation, or races between probe and read).

This function does not perform any I/O and does not modify socket state; it simply constructs and throws a SocketException with a clear message.

Parameters
[in]expectedThe number of bytes the caller expected to be present in the next datagram.
[in]actualThe number of bytes observed (either probed or received).
[in]isProbedKnownSet to true if actual comes from a size probe; set to false if it reflects the size actually received from a recv/recvfrom call.
Exceptions
SocketException
  • Always throws (logical error; not a system error).
  • Uses error code 0 and a message of the form: "UDP datagram size mismatch: expected <E>, <probed|received> <A>".
Note
This function always throws and never returns.
No system error is consulted or reported; this represents a violated size invariant in the caller’s logic rather than a kernel failure.
// Example: after probing size, enforce exact-size semantics
const std::size_t probed = probeNextDatagramSize();
const std::size_t received = recvExact(buf, probed);
if (received != probed) {
DatagramSocket::throwSizeMismatch(probed, received, true);
}
static void throwSizeMismatch(const std::size_t expected, const std::size_t actual, const bool isProbedKnown)
Throw a descriptive exception when a UDP datagram’s size differs from what was expected.
Definition DatagramSocket.hpp:4343
See also
readIntoBuffer(), DefaultDatagramReceiveSize, MaxDatagramPayloadSafe

◆ tryGetRemoteSockaddr()

bool DatagramSocket::tryGetRemoteSockaddr ( sockaddr_storage & out,
socklen_t & outLen ) const
nodiscardprotected

Retrieve the remote endpoint sockaddr for this socket, if available.

Determines the current remote peer (address + port) and writes it to the provided output buffers. The method prefers already-cached information:

  • If the socket is connected and a remote endpoint was cached (e.g., by connect()), it copies the cached value to the outputs with no syscall.
  • If the socket is connected but no cache is present, it performs a single getpeername() to obtain the peer and writes it to the outputs.
  • If the socket is unconnected, it returns the last-seen sender only if your receive paths have cached one; otherwise it indicates that no remote is known yet.

This function is const and does not mutate any internal cache; it only reads cached values if present, or queries the OS once when connected.

Parameters
[out]outDestination for the remote endpoint (sockaddr_storage).
[out]outLenReceives the byte size of out (e.g., sizeof(sockaddr_in) or sizeof(sockaddr_in6)).
Return values
trueA remote endpoint was available and has been written to out/outLen.
falseThe socket is unconnected and no last-seen sender has been cached yet.
Precondition
The socket must be open (isOpen() == true).
Exceptions
SocketException
  • If the socket is not open.
  • If getpeername() is required (connected, no cache) and it fails; the exception carries GetSocketError() and SocketErrorMessage(GetSocketError()).
Note
Complexity: O(1) when the remote is cached; otherwise one getpeername() call.
Thread-safety: intended for the socket’s owning thread. Do not call concurrently with close() or state mutations such as disconnect().
sockaddr_storage peer{};
socklen_t peerLen{};
if (!sock.tryGetRemoteSockaddr(peer, peerLen)) {
// Unconnected socket and no datagrams seen yet — no remote known.
} else {
// Use peer / peerLen (e.g., for logging or formatting).
}

◆ waitReady()

void DatagramSocket::waitReady ( Direction dir,
int timeoutMillis ) const

Block until the socket is ready for I/O or a timeout occurs.

Waits for the connected UDP socket to become ready for the requested operation(s) using a portable polling primitive (poll on POSIX, WSAPoll on Windows). This method does not change the socket’s blocking mode and is safe to call on both blocking and non-blocking sockets.

Timeout semantics

  • timeoutMillis < 0 → wait indefinitely (no timeout).
  • timeoutMillis == 0 → non-blocking poll (immediate). If not ready, throws SocketTimeoutException.
  • timeoutMillis > 0 → wait up to the specified milliseconds.

If an exceptional condition is reported by the OS (e.g., POLLERR, POLLNVAL, POLLHUP), this function retrieves SO_ERROR when available and throws a SocketException with that error code/message.

Parameters
[in]dirReadiness to wait for: Direction::Read, Direction::Write, or Direction::ReadWrite.
[in]timeoutMillisTimeout in milliseconds (see semantics above).
Precondition
getSocketFd() != INVALID_SOCKET
Exceptions
SocketTimeoutExceptionIf the requested readiness is not achieved before the timeout.
SocketExceptionOn polling failure or detected socket error (uses GetSocketError() and SocketErrorMessage()).
// Example: wait up to 500 ms to become writable, then send one datagram
void waitReady(Direction dir, int timeoutMillis) const
Block until the socket is ready for I/O or a timeout occurs.
Definition DatagramSocket.cpp:2085
@ Write
Wait until the socket is writable (can send a datagram without blocking).
Definition DatagramSocket.hpp:415

◆ write() [1/4]

void DatagramSocket::write ( const DatagramPacket & packet)

Send one UDP datagram using a packet’s buffer and optional explicit destination.

Emits exactly one datagram whose payload is packet.buffer. Behavior depends on whether the packet specifies a destination:

  • Packet has a destination (packet.hasDestination() is true): Uses the unconnected send path via sendUnconnectedTo(packet.address, packet.port, ...). That helper resolves A/AAAA, skips families that cannot carry the payload size, attempts one send to the first compatible candidate, and caches the last destination (without marking the socket as connected).
  • Packet has no destination: Requires the socket to be already connected. The method enforces the connected peer’s protocol maxima via enforceSendCapConnected(packet.buffer.size()) and sends once.

Processing steps: 1) Verify the socket is open. 2) If packet.buffer.empty(), return immediately (zero-length datagrams are valid but skipped). 3) If the packet carries a destination, forward to sendUnconnectedTo(...). 4) Otherwise, require isConnected() == true, guard size with enforceSendCapConnected(...), and send.

Atomicity: UDP is message-oriented; on success, the entire packet.buffer is sent as one datagram. On exception, no bytes are considered transmitted.

Parameters
[in]packetThe packet whose buffer supplies the payload and whose address/port (if present) select the destination for unconnected sends.
Precondition
getSocketFd() != INVALID_SOCKET
If !packet.hasDestination(), then isConnected() == true
Postcondition
On success, exactly packet.buffer.size() bytes are handed to the kernel as one datagram. Socket state and options are unchanged. Unconnected sends may update the cached last-remote endpoint for diagnostics, but do not connect the socket.
Exceptions
SocketException
  • Logical (error code = 0):
    • Socket is not open.
    • No destination in the packet and socket is not connected.
    • For connected sends, payload exceeds the permitted maximum for the peer’s family (detected by enforceSendCapConnected()).
    • For unconnected sends, no address family can carry the payload size (surfaced by sendUnconnectedTo()).
  • System (OS error + SocketErrorMessage(...)):
    • Resolution or send failures reported by the OS (e.g., ENETUNREACH, EHOSTUNREACH, ENOBUFS, EWOULDBLOCK / WSAEWOULDBLOCK on non-blocking sockets), or poll-derived errors inside helpers.
Note
Zero-length payloads: this method returns without sending. If your protocol needs to signal an empty frame, consider a prefix/marker instead of an empty datagram.
Since
1.0
See also
write(std::string_view), writeFrom(const void*, std::size_t), writeTo(std::string_view, Port, std::string_view), sendUnconnectedTo(std::string_view, Port, const void*, std::size_t), enforceSendCapConnected(std::size_t)

◆ write() [2/4]

template<typename T>
void jsocketpp::DatagramSocket::write ( const T & value) const
inline

Send one UDP datagram whose payload is the raw object representation of value.

Template Parameters
TTrivially copyable, standard-layout type whose in-memory object representation will be sent verbatim as the datagram payload. (See Implementation notes.)

Emits exactly one datagram containing the bytes of value. This method performs an immediate send attempt (no pre-wait). Use writeAll() or writeWithTimeout() if you need the call to block until the socket is writable.

Processing steps:

  1. Verifies the socket is open and connected.
  2. Computes sizeof(T) and enforces address-family maxima via enforceSendCapConnected(sizeof(T)) to preempt guaranteed EMSGSIZE failures.
  3. Transmits the payload in a single system call; on success, the entire object representation is handed to the kernel as one UDP datagram (no partial sends).

⚠️ Serialization & portability

  • The bytes sent are the raw object representation of T (including padding). Endianness, padding, and ABI differences make this suitable mainly for homogeneous peers or debugging. For interoperable protocols, prefer explicit serialization (fixed-width integers in network byte order, packed layouts, etc.).
  • If T contains padding, ensure it is initialized to avoid leaking stale memory.

Atomicity: UDP is message-oriented; on success, there are no partial sends. Any failure is reported via exception and no bytes are considered transmitted.

Parameters
[in]valueThe value to send; its bytes (object representation) become the datagram payload.
Precondition
getSocketFd() != INVALID_SOCKET
isConnected() == true
Postcondition
On success, exactly sizeof(T) bytes are queued to the kernel as a single datagram.
Exceptions
SocketException
  • Logical (error code = 0):
  • System (OS error code + SocketErrorMessage(...)):
    • Transient non-blocking condition (EWOULDBLOCK / WSAEWOULDBLOCK).
    • Resource/network issues (ENOBUFS, ENETUNREACH, EHOSTUNREACH, etc.).
Note
This method does not wait for writability. Use writeAll() (infinite wait) or writeWithTimeout() (bounded wait) for backpressure handling.
Since
1.0
See also
write(std::string_view), writeAll(), writeWithTimeout(), writeTo(std::string_view, Port, std::string_view), enforceSendCapConnected()
Implementation notes
Uses std::bit_cast<std::array<std::byte, sizeof(T)>> (C++20) to capture the exact object representation. Compile-time constraints:
static_assert(std::is_trivially_copyable_v<T>);
static_assert(std::is_standard_layout_v<T>);

◆ write() [3/4]

void DatagramSocket::write ( std::span< const std::byte > data) const

Send one UDP datagram to the connected peer from a raw byte span (no pre-wait).

Emits exactly one datagram containing the bytes referenced by data. This method performs an immediate send attempt:

  1. Verifies the socket is open and connected.
  2. If the span is empty, it returns immediately (zero-length datagrams are valid in UDP, but this implementation skips the syscall as a micro-optimization).
  3. Enforces protocol-level size limits for the connected peer’s address family via enforceSendCapConnected(data.size()) to preempt guaranteed EMSGSIZE failures.
  4. Transmits the payload in a single system call (no partial sends).

This function does not poll for writability. On non-blocking sockets, if the send buffer is full, the send may fail (e.g., EWOULDBLOCK/WSAEWOULDBLOCK) and a SocketException is thrown. If you need backpressure handling, use writeAll() (infinite wait) or writeWithTimeout() (bounded wait) instead.

Atomicity: UDP is message-oriented; on success the entire span is sent as one datagram. On exception, no bytes are considered transmitted.

Parameters
[in]dataContiguous read-only bytes to send as a single datagram.
Precondition
getSocketFd() != INVALID_SOCKET
isConnected() == true
Postcondition
On success, exactly data.size() bytes are handed to the kernel as one datagram.
Exceptions
SocketException
  • Logical (error code = 0):
  • System (OS error code + SocketErrorMessage(...)):
    • Transient non-blocking condition (EWOULDBLOCK / WSAEWOULDBLOCK).
    • Resource/network issues (ENOBUFS, ENETUNREACH, EHOSTUNREACH, etc.).
Note
This overload is ideal when you already have binary data as bytes. For textual data, prefer write(std::string_view). For POD types, see write<T>(const T&).
Zero-length payloads: this method returns without sending. If you must signal an “empty message,” consider a protocol marker instead of an empty datagram.
Since
1.0
See also
write(std::string_view), writeAll(), writeWithTimeout(), write(const T&), writeFrom(const void*, std::size_t), writev(std::span<const std::string_view>), enforceSendCapConnected()
// Example: send raw binary using std::byte
std::array<std::byte, 4> magic{ std::byte{0xDE}, std::byte{0xAD},
std::byte{0xBE}, std::byte{0xEF} };
sock.write(std::span<const std::byte>{magic});
// From an existing buffer:
const std::byte* p = reinterpret_cast<const std::byte*>(buffer.data());
sock.write(std::span<const std::byte>{p, buffer.size()});

◆ write() [4/4]

void DatagramSocket::write ( std::string_view message) const

Send one UDP datagram to the currently connected peer (no pre-wait).

Emits exactly one datagram containing the bytes in message. This method performs an immediate send attempt:

  1. Validates that the socket is open and connected.
  2. If the payload is empty, it returns immediately (zero-length datagrams are valid per UDP, but this implementation avoids the syscall as a micro-optimization).
  3. Enforces protocol-level size limits for the connected peer’s address family via enforceSendCapConnected(message.size()) (prevents guaranteed EMSGSIZE failures).
  4. Calls the internal single-syscall sender to transmit the datagram.

This function does not poll or wait for writability. On non-blocking sockets, if the send buffer is temporarily full, the underlying send may fail (e.g., EWOULDBLOCK/WSAEWOULDBLOCK) and a SocketException is thrown. If you need the method to wait until the socket is writable, use writeAll() or one of the timeout variants instead.

Atomicity: UDP is message-oriented; on success, the entire payload is sent in one datagram (no partial sends). Failures are reported via exceptions—no bytes are considered transmitted on exception.

Parameters
[in]messageBytes to send as a single datagram. Accepts std::string, string literals, and other contiguous character sequences via implicit conversion to std::string_view.
Precondition
getSocketFd() != INVALID_SOCKET
isConnected() == true
Postcondition
On success, exactly message.size() bytes are handed to the kernel as a single datagram. The connection state and socket options are unchanged.
Exceptions
SocketException
  • Logical errors (error code = 0):
  • System errors (OS error code + SocketErrorMessage(...)):
    • Transient non-blocking condition (EWOULDBLOCK / WSAEWOULDBLOCK).
    • Resource/network issues (ENOBUFS, ENETUNREACH, EHOSTUNREACH, etc.).
    • Other send failures surfaced by the OS.
Note
Zero-length payloads: this method returns without sending. If you need to intentionally transmit an empty datagram as a signal, use an explicit flag in your protocol or send a 1-byte marker instead.
See also
writeAll(), writeWithTimeout(), writeTo(), enforceSendCapConnected()
// ... socket opened and connected elsewhere ...
sock.write("ping"); // immediate attempt; may throw on EWOULDBLOCK
sock.write(std::string_view{"hello"}); // same, using string_view explicitly
void write(std::string_view message) const
Send one UDP datagram to the currently connected peer (no pre-wait).
Definition DatagramSocket.cpp:458
Since
1.0

◆ writeAll()

void DatagramSocket::writeAll ( std::string_view message) const

Send one UDP datagram to the connected peer, waiting indefinitely for writability.

Emits exactly one datagram containing message. Unlike write(), this method pre-waits for the socket to become writable so it behaves consistently on both blocking and non-blocking sockets:

  1. Verifies the socket is open and connected.
  2. If the payload is empty, returns immediately (zero-length UDP datagrams are valid, but this implementation skips the syscall as a micro-optimization).
  3. Enforces protocol-level size limits for the connected peer via enforceSendCapConnected(message.size()).
  4. Calls waitReady(Direction::Write, -1) to wait without timeout until writable.
  5. Transmits the datagram in a single syscall (no partial sends).

Atomicity: On success the entire payload is sent in one datagram. On exception, no bytes are considered transmitted.

Parameters
[in]messageBytes to send as a single datagram.
Precondition
getSocketFd() != INVALID_SOCKET
isConnected() == true
Postcondition
On success, exactly message.size() bytes are handed to the kernel as one datagram.
Exceptions
SocketException
  • Logical (error code = 0): socket not open/connected; payload exceeds permitted maximum for the connected family (via enforceSendCapConnected()).
  • System (OS error + SocketErrorMessage(...)): polling or send failures.
Note
This method never throws SocketTimeoutException because it waits indefinitely. For a bounded wait, use writeWithTimeout().
Since
1.0
See also
write(std::string_view), writeWithTimeout(std::string_view, int), writevAll(std::span<const std::string_view>), enforceSendCapConnected(), waitReady()

◆ writeFrom()

void DatagramSocket::writeFrom ( const void * data,
std::size_t len ) const

Send one UDP datagram to the connected peer from a raw memory buffer (no pre-wait).

Emits exactly one datagram containing the first len bytes starting at data. This method performs an immediate send attempt (it does not poll for writability):

  1. Verifies the socket is open and connected.
  2. If len is zero, returns immediately (zero-length UDP datagrams are valid, but this implementation skips the syscall as a micro-optimization).
  3. Enforces protocol-level size limits for the connected peer’s family via enforceSendCapConnected(len) to preempt guaranteed EMSGSIZE.
  4. Transmits the datagram in a single system call (no partial sends).

This function does not pre-wait for writability. On non-blocking sockets, if the send buffer is temporarily full, the underlying send may fail (e.g., EWOULDBLOCK / WSAEWOULDBLOCK) and a SocketException is thrown. For blocking behavior, use writeAll() (infinite wait) or writeWithTimeout() (bounded wait).

Ownership/Lifetime: The memory referenced by data is not copied or retained beyond the duration of the call; it must remain valid and readable until the call returns.

Atomicity: UDP is message-oriented; on success, the entire buffer is sent as one datagram. On exception, no bytes are considered transmitted.

Parameters
[in]dataPointer to the first byte of the payload. May be nullptr iff len == 0.
[in]lenNumber of bytes to send as a single datagram.
Precondition
getSocketFd() != INVALID_SOCKET
isConnected() == true
data != nullptr || len == 0
Postcondition
On success, exactly len bytes are handed to the kernel as one datagram. Socket state and options are unchanged.
Exceptions
SocketException
  • Logical (error code = 0):
  • System (OS error + SocketErrorMessage(...)):
    • Transient non-blocking condition (EWOULDBLOCK, WSAEWOULDBLOCK).
    • Resource/network issues (ENOBUFS, ENETUNREACH, EHOSTUNREACH, etc.).
Note
If your payload is already in std::byte form, prefer write(std::span<const std::byte>). For text, prefer write(std::string_view). For POD objects, consider write<T>(const T&).
Since
1.0
See also
write(std::string_view), write(std::span<const std::byte>), writeAll(std::string_view), writeWithTimeout(std::string_view, int), writev(std::span<const std::string_view>), enforceSendCapConnected(std::size_t)
// Example: send a raw buffer
std::array<std::uint8_t, 4> buf{0xDE, 0xAD, 0xBE, 0xEF};
sock.writeFrom(buf.data(), buf.size());
// From a std::vector<char>
std::vector<char> payload = get_payload();
sock.writeFrom(payload.data(), payload.size());

◆ writePrefixed() [1/2]

template<typename T>
void jsocketpp::DatagramSocket::writePrefixed ( const std::span< const std::byte > payload) const
inline

Send a length-prefixed UDP datagram to the connected peer from a byte span (no pre-wait).

Template Parameters
TUnsigned integral type for the length prefix.

Builds [ prefix(T, big-endian) | payload ] and forwards to sendPrefixedConnected<T>(). Zero-length payloads yield a prefix-only datagram. This method performs an immediate send attempt (no pre-wait).

Parameters
[in]payloadBinary payload to append after the length prefix.
Precondition
getSocketFd() != INVALID_SOCKET
isConnected() == true
Exceptions
SocketException(same categories as the std::string_view overload).
Since
1.0
See also
sendPrefixedConnected<T>(std::span<const std::byte>), writePrefixed<T>(std::string_view), encodeLengthPrefixBE<T>(std::size_t), enforceSendCapConnected(std::size_t)

◆ writePrefixed() [2/2]

template<typename T>
void jsocketpp::DatagramSocket::writePrefixed ( const std::string_view payload) const
inline

Send a length-prefixed UDP datagram to the connected peer from text bytes (no pre-wait).

Template Parameters
TUnsigned integral type for the length prefix (e.g., std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t). A compile-time check in the helper enforces this.

Wraps the payload as [ prefix(T, big-endian) | payload ] and forwards to sendPrefixedConnected<T>(). Zero-length payloads are valid: a prefix-only datagram is sent. This method performs an immediate send attempt (no pre-wait).

Parameters
[in]payloadText bytes to send after the length prefix.
Precondition
getSocketFd() != INVALID_SOCKET
isConnected() == true
Exceptions
SocketException
  • Logical (error=0): socket not open/connected; payload.size() exceeds std::numeric_limits<T>::max(); total size exceeds the connected family’s limit.
  • System (OS error + SocketErrorMessage(...)): send failures (e.g., EWOULDBLOCK, ENOBUFS).
Since
1.0
See also
sendPrefixedConnected<T>(std::span<const std::byte>), writePrefixedTo<T>(std::string_view, Port, std::string_view), encodeLengthPrefixBE<T>(std::size_t), enforceSendCapConnected(std::size_t)

◆ writePrefixedTo() [1/2]

template<typename T>
void jsocketpp::DatagramSocket::writePrefixedTo ( const std::string_view host,
const Port port,
const std::span< const std::byte > payload ) const
inline

Send a length-prefixed UDP datagram to (host, port) from a byte span (unconnected path).

Template Parameters
TUnsigned integral type for the length prefix.

Builds [ prefix(T, big-endian) | payload ] and forwards to sendPrefixedUnconnected<T>(). The helper resolves and selects a compatible destination (skipping families that can’t carry the frame) and sends once.

Parameters
[in]hostDestination hostname or numeric address (IPv4/IPv6).
[in]portDestination UDP port (> 0).
[in]payloadBinary payload to append after the length prefix.
Precondition
getSocketFd() != INVALID_SOCKET
Exceptions
SocketException(same categories as the text overload).
Since
1.0
See also
sendPrefixedUnconnected<T>(std::string_view, Port, std::span<const std::byte>), writePrefixedTo<T>(std::string_view, Port, std::string_view), encodeLengthPrefixBE<T>(std::size_t), sendUnconnectedTo(std::string_view, Port, const void*, std::size_t)

◆ writePrefixedTo() [2/2]

template<typename T>
void jsocketpp::DatagramSocket::writePrefixedTo ( const std::string_view host,
const Port port,
const std::string_view payload ) const
inline

Send a length-prefixed UDP datagram to (host, port) from text bytes (unconnected path).

Template Parameters
TUnsigned integral type for the length prefix.

Builds [ prefix(T, big-endian) | payload ] and forwards to sendPrefixedUnconnected<T>(), which resolves A/AAAA, skips families that cannot carry the frame, and sends once to the first compatible destination. Zero-length payloads produce a prefix-only datagram.

Parameters
[in]hostDestination hostname or numeric address (IPv4/IPv6).
[in]portDestination UDP port (> 0).
[in]payloadText bytes to append after the length prefix.
Precondition
getSocketFd() != INVALID_SOCKET
Exceptions
SocketException
  • Logical (error=0): socket not open; payload.size() exceeds std::numeric_limits<T>::max(); or no address family can carry the total size (surfaced by the helper).
  • System (OS error + SocketErrorMessage(...)): resolution/send failures.
Since
1.0
See also
sendPrefixedUnconnected<T>(std::string_view, Port, std::span<const std::byte>), writePrefixedTo<T>(std::string_view, Port, std::span<const std::byte>), encodeLengthPrefixBE<T>(std::size_t), sendUnconnectedTo(std::string_view, Port, const void*, std::size_t)

◆ writeTo() [1/3]

template<typename T>
void jsocketpp::DatagramSocket::writeTo ( const std::string_view host,
const Port port,
const T & value ) const
inline

Send one unconnected UDP datagram to (host, port) containing the raw bytes of value.

Template Parameters
TTrivially copyable, standard-layout type whose in-memory object representation will be sent verbatim as the datagram payload. Compile-time checks in the implementation enforce these constraints.

Emits exactly one datagram whose payload is the raw bytes of value. This overload uses the unconnected send path and delegates to sendUnconnectedTo(), which:

  • Resolves A/AAAA candidates for host.
  • Skips any address family whose theoretical UDP maximum cannot carry sizeof(T).
  • Attempts a single send to the first compatible candidate, returning on success.
  • Caches the last destination endpoint for diagnostics (does not connect the socket).

Steps performed by this method: 1) Verify the socket is open. 2) If sizeof(T) == 0, return immediately. 3) Bit-cast value to a contiguous byte buffer. 4) Forward to sendUnconnectedTo(host, port, buf, sizeof(T)).

This function does not poll for writability. On non-blocking sockets, if a send is attempted and the send buffer is full, the underlying send may fail (EWOULDBLOCK / WSAEWOULDBLOCK) and will be surfaced as a SocketException. For blocking semantics on a connected socket, prefer writeAll() or writeWithTimeout().

Serialization and portability:

  • The bytes sent are the raw object representation of T (including any padding). Endianness, padding, and ABI differences mean this is typically suitable only for homogeneous peers or debugging. For interoperable protocols, use explicit serialization (fixed-width integers in network byte order, packed layouts, and so on).
  • If T contains padding, ensure it is initialized to avoid leaking stale memory.

Atomicity:

  • UDP is message-oriented; on success, the entire sizeof(T) bytes are sent as one datagram. On exception, no bytes are considered transmitted.
Parameters
[in]hostDestination hostname or numeric address (IPv4/IPv6).
[in]portDestination UDP port (> 0).
[in]valueThe value whose bytes form the datagram payload.
Precondition
getSocketFd() != INVALID_SOCKET
Postcondition
On success, exactly sizeof(T) bytes are handed to the kernel as one datagram. Socket state and options are unchanged. The last-remote endpoint may be cached internally for diagnostics.
Exceptions
SocketException
  • Logical (error code = 0):
    • Socket is not open.
    • No address family can carry sizeof(T) (for example, payload exceeds IPv4 limit and only A records are available; surfaced by sendUnconnectedTo() with a clear message).
  • System (OS error + SocketErrorMessage(...)):
    • Resolution or send failures reported by the OS (for example, EAI_*, ENETUNREACH, EHOSTUNREACH, ENOBUFS, EWOULDBLOCK).
Since
1.0
See also
writeTo(std::string_view, Port, std::string_view), write(std::string_view), writeFrom(const void*, std::size_t), sendUnconnectedTo(std::string_view, Port, const void*, std::size_t)
// Example: send a POD header to a destination without connecting the socket
struct Header {
std::uint32_t magic;
std::uint16_t version;
std::uint16_t flags;
};
static_assert(std::is_trivially_copyable_v<Header> && std::is_standard_layout_v<Header>);
Header h{0xABCD1234u, 1u, 0u};
sock.writeTo("example.com", 5000, h);

◆ writeTo() [2/3]

void DatagramSocket::writeTo ( std::string_view host,
Port port,
std::span< const std::byte > data )

Send one unconnected UDP datagram to (host, port) from a raw byte span (no pre-wait).

Emits exactly one datagram containing data to the specified destination. This overload uses the unconnected send path and delegates to sendUnconnectedTo(), which:

  • Resolves A/AAAA candidates for host.
  • Skips any address family whose theoretical UDP maximum cannot carry the payload size (IPv4 vs IPv6 caps).
  • Attempts a single send to the first compatible candidate, returning on success.
  • Caches the last destination endpoint for diagnostics (does not connect the socket).

Steps performed by this method: 1) Verify the socket is open. 2) If data.empty(), return immediately (zero-length UDP datagrams are valid, but this implementation skips the syscall as a micro-optimization). 3) Forward to sendUnconnectedTo(host, port, data.data(), data.size()).

This function does not poll for writability. On non-blocking sockets, if an attempt is made and the send buffer is full, the underlying send may fail (EWOULDBLOCK / WSAEWOULDBLOCK) and will be surfaced as a SocketException. For blocking semantics on a connected socket, prefer writeAll() or writeWithTimeout().

Atomicity: UDP is message-oriented; on success, the entire span is sent as one datagram. On exception, no bytes are considered transmitted.

Parameters
[in]hostDestination hostname or numeric address (IPv4/IPv6).
[in]portDestination UDP port (> 0).
[in]dataContiguous read-only bytes to send as a single datagram.
Precondition
getSocketFd() != INVALID_SOCKET
Postcondition
On success, exactly data.size() bytes are handed to the kernel as one datagram. Socket state and options are unchanged. The last-remote endpoint may be cached internally for diagnostics.
Exceptions
SocketException
  • Logical (error code = 0):
    • Socket is not open.
    • No address family can carry the datagram size (for example, payload exceeds IPv4 limit and only A records are available; surfaced by sendUnconnectedTo() with a clear message).
  • System (OS error + SocketErrorMessage(...)):
    • Resolution or send failures reported by the OS (for example, EAI_*, ENETUNREACH, EHOSTUNREACH, ENOBUFS, EWOULDBLOCK).
Note
Family-specific size enforcement (IPv4 vs IPv6) and destination selection are handled inside sendUnconnectedTo(). This method performs no pre-wait; if you need bounded or indefinite waiting, connect the socket and use writeWithTimeout() or writeAll().
Since
1.0
See also
writeTo(std::string_view, Port, std::string_view), write(std::span<const std::byte>), writeAll(std::string_view), writeWithTimeout(std::string_view, int), sendUnconnectedTo(std::string_view, Port, const void*, std::size_t)
// Example: send binary payload to a destination without connecting the socket
std::array<std::byte, 4> magic{std::byte{0xDE}, std::byte{0xAD},
std::byte{0xBE}, std::byte{0xEF}};
sock.writeTo("239.0.0.1", 5000, std::span<const std::byte>{magic});
// From a dynamic buffer
std::vector<std::byte> payload(3);
payload[0] = std::byte{0x01};
payload[1] = std::byte{0x02};
payload[2] = std::byte{0x03};
sock.writeTo("2001:db8::1", 6000, std::span<const std::byte>{payload.data(), payload.size()});

◆ writeTo() [3/3]

void DatagramSocket::writeTo ( std::string_view host,
Port port,
std::string_view message )

Send one unconnected UDP datagram to (host, port) from text bytes (no pre-wait).

Emits exactly one datagram containing message to the specified destination. This overload uses the unconnected send path and delegates the heavy lifting to sendUnconnectedTo(), which:

  • Resolves A/AAAA candidates for host.
  • Skips any address family whose theoretical UDP maximum cannot carry the payload size (IPv4 vs IPv6 caps).
  • Attempts a single send to the first compatible candidate, returning on success.
  • Caches the last destination endpoint for diagnostics (does not mark the socket as connected).

Steps performed by this method: 1) Verify the socket is open. 2) If message.empty(), return immediately (zero-length UDP datagrams are valid, but this implementation skips the syscall as a micro-optimization). 3) Forward to sendUnconnectedTo(host, port, message.data(), message.size()).

This function does not poll for writability. On non-blocking sockets, if an attempt is made and the send buffer is full, the underlying send may fail (EWOULDBLOCK / WSAEWOULDBLOCK) and will be surfaced as a SocketException. For blocking semantics on a connected socket, prefer writeAll() or writeWithTimeout().

Atomicity: UDP is message-oriented; on success, the entire payload is sent as one datagram. On exception, no bytes are considered transmitted.

Parameters
[in]hostDestination hostname or numeric address (IPv4/IPv6).
[in]portDestination UDP port (> 0).
[in]messageBytes to send as a single datagram (accepts std::string, string literals, etc., via implicit conversion to std::string_view).
Precondition
getSocketFd() != INVALID_SOCKET
Postcondition
On success, exactly message.size() bytes are handed to the kernel as one datagram. Socket state and options are unchanged. The last-remote endpoint may be cached internally for diagnostics.
Exceptions
SocketException
  • Logical (error code = 0):
    • Socket is not open.
    • No address family can carry the datagram size (e.g., payload exceeds IPv4 limit and only A records are available; surfaced by sendUnconnectedTo() with a clear message).
  • System (OS error + SocketErrorMessage(...)):
    • Resolution or send failures reported by the OS (e.g., EAI_*, ENETUNREACH, EHOSTUNREACH, ENOBUFS, EWOULDBLOCK).
Note
Family-specific size enforcement (IPv4 vs IPv6) and destination selection are handled inside sendUnconnectedTo(). This method performs no pre-wait; if you need bounded or indefinite waiting, connect the socket and use writeWithTimeout() or writeAll().
Since
1.0
See also
write(std::string_view), writeAll(std::string_view), writeWithTimeout(std::string_view, int), writePrefixedTo<T>(std::string_view, Port, std::string_view), sendUnconnectedTo(std::string_view, Port, const void*, std::size_t)
// Example: send a message to a host/port without connecting the socket
sock.writeTo("example.com", 8125, "metric:1|c");
// IPv6 numeric address is fine too:
sock.writeTo("2001:db8::1", 5000, "hello");

◆ writev()

void DatagramSocket::writev ( std::span< const std::string_view > buffers) const

Send one UDP datagram to the connected peer by concatenating multiple fragments (no pre-wait).

Emits exactly one datagram whose payload is the concatenation of all strings in buffers. This method performs an immediate send attempt (it does not wait for writability):

  1. Verifies the socket is open and connected.
  2. Computes the total byte count sum(buffers[i].size()). If the sum is zero, returns immediately (zero-length UDP datagrams are valid, but this implementation skips the syscall).
  3. Enforces protocol-level maxima for the connected peer’s family via enforceSendCapConnected(total) to preempt guaranteed EMSGSIZE.
  4. Sends in a single syscall:
    • Fast path: if there is exactly one fragment, it is sent directly.
    • Otherwise, the fragments are coalesced into a temporary contiguous buffer and sent once.

This function does not pre-wait for writability. On non-blocking sockets, if the send buffer is full, the send may fail (e.g., EWOULDBLOCK / WSAEWOULDBLOCK) and a SocketException is thrown. Use writevAll() or writeWithTimeout() for blocking behavior.

Atomicity: UDP is message-oriented; on success the entire concatenated payload is sent as a single datagram. On exception, no bytes are considered transmitted.

Parameters
[in]buffersSequence of string fragments that will be concatenated in-order into the datagram payload. Individual elements may be empty.
Precondition
getSocketFd() != INVALID_SOCKET
isConnected() == true
Postcondition
On success, exactly the sum of all fragment sizes is handed to the kernel as one datagram.
Exceptions
SocketException
  • Logical (error code = 0): socket not open/connected; total payload exceeds the permitted maximum for the connected peer’s family (detected by enforceSendCapConnected()).
  • System (OS error + SocketErrorMessage(...)): send failures such as EWOULDBLOCK, ENOBUFS, ENETUNREACH, EHOSTUNREACH, etc.
Note
If you later add a scatter/gather internal::sendExactv(...), this method can switch to a vectored send to avoid the temporary copy in the multi-fragment case.
Since
1.0
See also
writevAll(std::span<const std::string_view>), write(std::string_view), writeAll(std::string_view), writeWithTimeout(std::string_view, int), enforceSendCapConnected(std::size_t)
// Example: send header + body as one UDP datagram
std::string_view header = "HDR:";
std::string_view body = "payload";
sock.writev({header, body}); // immediate attempt; may throw on EWOULDBLOCK

◆ writevAll()

void DatagramSocket::writevAll ( std::span< const std::string_view > buffers) const

Send one UDP datagram to the connected peer by concatenating multiple fragments, waiting indefinitely.

Emits exactly one datagram whose payload is the concatenation of all strings in buffers. Unlike writev(), this method pre-waits for writability so it behaves consistently on both blocking and non-blocking sockets:

  1. Verifies the socket is open and connected.
  2. Computes the total byte count sum(buffers[i].size()). If the sum is zero, returns immediately (zero-length UDP datagrams are valid, but this implementation skips the syscall).
  3. Enforces protocol-level maxima for the connected peer’s family via enforceSendCapConnected(total) to preempt guaranteed EMSGSIZE.
  4. Calls waitReady(Direction::Write, -1) to wait without timeout until the socket is writable (poll errors are surfaced as SocketException).
  5. Sends in a single syscall:
    • Fast path: if there is exactly one fragment, it is sent directly.
    • Otherwise, the fragments are coalesced into a temporary contiguous buffer and sent once.

Atomicity: UDP is message-oriented; on success, the entire concatenated payload is sent as a single datagram. On exception, no bytes are considered transmitted.

Parameters
[in]buffersSequence of string fragments concatenated in-order into the datagram payload. Individual elements may be empty.
Precondition
getSocketFd() != INVALID_SOCKET
isConnected() == true
Postcondition
On success, exactly the sum of all fragment sizes is handed to the kernel as one datagram. Socket state and options are unchanged.
Exceptions
SocketException
  • Logical (error code = 0): socket not open/connected; total payload exceeds the permitted maximum for the connected peer’s family (detected by enforceSendCapConnected()).
  • System (OS error + SocketErrorMessage(...)): polling or send failures (e.g., POLLERR, POLLNVAL, POLLHUP, ENOBUFS, ENETUNREACH, EHOSTUNREACH, etc.).
Note
This method never throws SocketTimeoutException because it waits indefinitely. For a bounded wait, use writeWithTimeout().
If you later add a scatter/gather internal::sendExactv(...), this method can switch to a vectored send to avoid the temporary copy in the multi-fragment case.
Since
1.0
See also
writev(std::span<const std::string_view>), write(std::string_view), writeAll(std::string_view), writeWithTimeout(std::string_view, int), enforceSendCapConnected(std::size_t), waitReady(Direction, int)
// Example: send header + separator + body as one UDP datagram, blocking until writable
std::string_view hdr = "HDR";
std::string_view sep = ":";
std::string_view body = "payload";
sock.writevAll({hdr, sep, body});

◆ writeWithTimeout()

void DatagramSocket::writeWithTimeout ( std::string_view data,
int timeoutMillis ) const

Send one UDP datagram to the connected peer, waiting up to timeoutMillis for writability.

Emits exactly one datagram containing data. This method bounds the wait for socket writability, then performs a single send:

  1. Verifies the socket is open and connected.
  2. If the payload is empty, returns immediately (zero-length UDP datagrams are valid, but this implementation skips the syscall as a micro-optimization).
  3. Enforces protocol-level size limits for the connected peer’s address family via enforceSendCapConnected(data.size()) to preempt guaranteed EMSGSIZE.
  4. Calls waitReady(Direction::Write, timeoutMillis); if the socket does not become writable before the timeout, a SocketTimeoutException is thrown.
  5. On readiness, transmits the datagram in a single system call (no partial sends).

Timeout semantics (delegated to waitReady()):

  • timeoutMillis > 0 — wait up to the specified milliseconds.
  • timeoutMillis == 0 — non-blocking poll (immediate).
  • timeoutMillis < 0 — wait indefinitely (equivalent to writeAll() behavior).

Atomicity: UDP is message-oriented; on success, the entire payload is sent as one datagram. On exception, no bytes are considered transmitted.

Parameters
[in]dataBytes to send as a single datagram (accepts std::string, string literals, etc., via implicit conversion to std::string_view).
[in]timeoutMillisSee timeout semantics above.
Precondition
getSocketFd() != INVALID_SOCKET
isConnected() == true
Postcondition
On success, exactly data.size() bytes are handed to the kernel as one datagram. Socket state and options are unchanged.
Exceptions
SocketTimeoutExceptionIf the socket does not become writable within timeoutMillis (when it is >= 0).
SocketException
  • Logical (error code = 0): socket not open/connected; payload exceeds the permitted maximum for the connected peer’s family (detected by enforceSendCapConnected()).
  • System (OS error + SocketErrorMessage(...)): polling or send failures (e.g., POLLERR, POLLNVAL, POLLHUP, EWOULDBLOCK, ENOBUFS, ENETUNREACH, etc.).
Note
Prefer writeAll() when you intentionally want an infinite wait; pass a negative timeoutMillis to mimic that behavior if you must stick to a single API.
For an immediate, no-wait attempt, use write() instead.
Since
1.0
See also
write(std::string_view), writeAll(std::string_view), writevAll(std::span<const std::string_view>), enforceSendCapConnected(std::size_t), waitReady(Direction, int)
// Example: send with a 500 ms bound
sock.writeWithTimeout("payload", 500); // throws SocketTimeoutException on timeout
// Immediate attempt (non-blocking poll)
sock.writeWithTimeout("ping", 0);
// Equivalent to writeAll() (infinite wait)
sock.writeWithTimeout("large message", -1);

◆ ~DatagramSocket()

DatagramSocket::~DatagramSocket ( )
overridenoexcept

Destructor for DatagramSocket. Ensures socket resources are released.

Automatically closes the underlying UDP socket and releases all associated system resources. This follows RAII principles, guaranteeing cleanup when the object goes out of scope.

  • Closes the socket file descriptor (using close() or platform equivalent)
  • Suppresses all exceptions during cleanup to maintain noexcept guarantees
  • Prevents resource leaks even in exception scenarios
Note
Errors during destruction are ignored. For explicit error handling, call close() manually.
Do not use a DatagramSocket after destruction or move.
See also
close()