SFML - Simple and Fast Multimedia Library

SFML 3.1.0
Loading...
Searching...
No Matches
Public Types | Public Member Functions | List of all members
sf::SocketSelector Class Reference
Network module

Multiplexer that allows to read from multiple sockets. More...

`#include <SFML/Network/SocketSelector.hpp>`

## Public Types
enum | : ReadinessType { Receive = 1 << 0 , Send = 1 << 1 }
| Type of readiness to check for. More...
using | ReadinessType = std::uint32_t
| Bitwise combination of readiness types.

## Public Member Functions
| SocketSelector ()
| Default constructor.
| ~SocketSelector ()
| Destructor.
| SocketSelector (const SocketSelector &copy)
| Copy constructor.
SocketSelector & | operator= (const SocketSelector &right)
| Overload of assignment operator.
| SocketSelector (SocketSelector &&) noexcept
| Move constructor.
SocketSelector & | operator= (SocketSelector &&) noexcept
| Move assignment.
bool | add (const Socket &socket, ReadinessType readinessType=Receive, std::function< void(ReadinessType readinessType)> readyCallback={})
| Add a new socket to the selector.
bool | remove (const Socket &socket)
| Remove a socket from the selector.
void | clear ()
| Remove all the sockets stored in the selector.
bool | wait (Time timeout=Time::Zero)
| Wait until one or more sockets are ready to receive or send.
bool | isReady (const Socket &socket, ReadinessType readinessType=Receive) const
| Test a socket to know if it is ready to receive or send data.
void | dispatchReadyCallbacks ()
| Dispatch callbacks of ready sockets.

## Detailed Description

Multiplexer that allows to read from multiple sockets.

Socket selectors provide a way to wait until data can be received or sent on a set of sockets, instead of just one.

This is convenient when you have multiple sockets that may possibly receive data, but you don't know which one will be ready first. In particular, it avoids to use a thread for each socket; with selectors, a single thread can handle all the sockets. When sending large amounts of data, the socket send buffer might fill up and you will have to wait for the data to actually be sent over the network connection before attempting to send more data.

All types of sockets can be used in a selector:

- sf::TcpListener
- sf::TcpSocket
- sf::UdpSocket

A selector doesn't store its own copies of the sockets (socket classes are not copyable anyway), it simply keeps a reference to the original sockets that you pass to the "add" function. Therefore, you can't use the selector as a socket container, you must store them outside and make sure that they are alive as long as they are used in the selector.

Using a selector is simple:

- populate the selector with all the sockets that you want to observe
- make it wait until there is data available or data can be sent on any of the sockets
- test each socket to find out which ones are ready for receiving or sending

If scalability is a concern, using callbacks is also possible:

- add all the sockets that you want to observe to the selector with their own ready callbacks
- make the selector wait until there is data available or data can be sent on any of the sockets
- dispatch the callbacks of the sockets that became ready during the wait

Usage example:

// Create a socket to listen to new connections
sf::TcpListener listener;
if (listener.listen(55001) != sf::Socket::Status::Done)
{
// Handle error...
}
// Create a list to store the future clients
std::vector<sf::TcpSocket> clients;
// Create a selector
sf::SocketSelector selector;
// Add the listener to the selector
selector.add(listener);
// Endless loop that waits for new connections
while (running)
{
// Make the selector wait for data on any socket
if (selector.wait())
{
// Test the listener
if (selector.isReady(listener))
{
// The listener is ready: there is a pending connection
sf::TcpSocket client;
if (listener.accept(client) == sf::Socket::Status::Done)
{
// Add the new client to the selector so that we will
// be notified when they send something
selector.add(client);
// Add the new client to the clients list
clients.push_back(std::move(client));
}
else
{
// Handle error...
}
}
else
{
// The listener socket is not ready, test all other sockets (the clients)
for (sf::TcpSocket& client : clients)
{
if (selector.isReady(client))
{
// The client has sent some data, we can receive it
sf::Packet packet;
if (client.receive(packet) == sf::Socket::Status::Done)
{
...
}
}
}
}
}
}
sf::SocketSelector
Multiplexer that allows to read from multiple sockets.
Definition SocketSelector.hpp:49
sf::SocketSelector::isReady
bool isReady(const Socket &socket, ReadinessType readinessType=Receive) const
Test a socket to know if it is ready to receive or send data.
sf::SocketSelector::wait
bool wait(Time timeout=Time::Zero)
Wait until one or more sockets are ready to receive or send.
sf::SocketSelector::add
bool add(const Socket &socket, ReadinessType readinessType=Receive, std::function< void(ReadinessType readinessType)> readyCallback={})
Add a new socket to the selector.
sf::Socket::Status::Done
@ Done
The socket has sent / received the data.
Definition Socket.hpp:51
sf::TcpListener
Socket that listens to new TCP connections.
Definition TcpListener.hpp:45
sf::TcpListener::listen
Status listen(unsigned short port, IpAddress address=IpAddress::Any)
Start listening for incoming connection attempts.
sf::TcpListener::accept
Status accept(TcpSocket &socket)
Accept a new connection.
sf::TcpSocket
Specialized socket using the TCP protocol.
Definition TcpSocket.hpp:58
sf::TcpSocket::receive
Status receive(void *data, std::size_t size, std::size_t &received)
Receive raw data from the remote peer.

Usage example with callbacks:

// Create a socket to listen to new connections
sf::TcpListener listener;
if (listener.listen(55001) != sf::Socket::Status::Done)
{
// Handle error...
}
// Create a list to store the future clients
// We use a std::list here because modifications
// don't invalidate references to existing elements
std::list<sf::TcpSocket> clients;
// Create a selector
sf::SocketSelector selector;
// Listeners can only become ready to receive so we don't
// have to check the readiness type in their callback
const auto listenerCallback = [&](sf::SocketSelector::ReadinessType)
{
// The listener is ready: there is a pending connection
sf::TcpSocket newSocket;
if (listener.accept(newSocket) == sf::Socket::Status::Done)
{
// Add the new client to the clients list
auto& client = clients.emplace_back(std::move(newSocket));
const auto clientCallback = [&client](sf::SocketSelector::ReadinessType readinessType)
{
if (readinessType & sf::SocketSelector::Receive)
{
// The client has sent some data, we can receive it
sf::Packet packet;
if (client.receive(packet) == sf::Socket::Status::Done)
{
...
}
}
};
// Add the new client to the selector with an attached
// callback that will be called when they send something
selector.add(client, sf::SocketSelector::Receive, clientCallback);
}
else
{
// Handle error...
}
};
// Add the listener to the selector with an attached callback
selector.add(listener, sf::SocketSelector::Receive, listenerCallback);
// Endless loop that waits for new connections and receives client data
while (running)
{
// Make the selector wait for sockets to become ready and dispatch their callbacks
if (selector.wait())
selector.dispatchReadyCallbacks();
}
sf::Packet
Utility class to build blocks of data to transfer over the network.
Definition Packet.hpp:49
sf::SocketSelector::Receive
@ Receive
Check if sockets are ready to be received from.
Definition SocketSelector.hpp:59
sf::SocketSelector::ReadinessType
std::uint32_t ReadinessType
Bitwise combination of readiness types.
Definition SocketSelector.hpp:51
sf::SocketSelector::dispatchReadyCallbacks
void dispatchReadyCallbacks()
Dispatch callbacks of ready sockets.

See also
  sf::Socket

Definition at line 48 of file SocketSelector.hpp.

## Member Typedef Documentation

## ◆ ReadinessType

using sf::SocketSelector::ReadinessType = std::uint32_t

Bitwise combination of readiness types.

Definition at line 51 of file SocketSelector.hpp.

## Member Enumeration Documentation

## ◆ anonymous enum

anonymous enum : ReadinessType

Type of readiness to check for.

Enumerator
Receive | Check if sockets are ready to be received from.
Send | Check if sockets are ready to be sent to.

Definition at line 57 of file SocketSelector.hpp.

## Constructor & Destructor Documentation

## ◆ SocketSelector() [1/3]

sf::SocketSelector::SocketSelector | ( |  | ) |

Default constructor.

## ◆ ~SocketSelector()

sf::SocketSelector::~SocketSelector | ( |  | ) |

Destructor.

## ◆ SocketSelector() [2/3]

sf::SocketSelector::SocketSelector | ( | const SocketSelector & | copy | ) |

Copy constructor.

Parameters

  copy | Instance to copy

## ◆ SocketSelector() [3/3]

sf::SocketSelector::SocketSelector | ( | SocketSelector && |  | ) |
| noexcept

Move constructor.

## Member Function Documentation

## ◆ add()

bool sf::SocketSelector::add | ( | const Socket & | socket,
|  | ReadinessType | readinessType = Receive,
|  | std::function< void(ReadinessType readinessType)> | readyCallback = {} )

Add a new socket to the selector.

The type of readiness to wait for can be specified. Specifying SocketSelector::Receive will wait for the socket to become ready to receive data from, specifying SocketSelector::Send will wait for the socket to become ready to send data on. Specifying SocketSelector::Receive | SocketSelector::Send will wait for the socket to become either ready to send or receive data on.

Adding a socket after it has already been added will just overwrite the existing readiness type with the new value.

This function keeps a weak reference to the socket, so you have to make sure that the socket is not destroyed while it is stored in the selector. This function does nothing if the socket is not valid.

When adding a socket to the selector you can also attach a callback along with it. The callback is called by dispatchReadyCallbacks when a socket is determined to be ready after a call to wait.

Using attached callbacks instead of having to individually call isReady on every socket after every call to wait allows for scaling up to a large number of sockets. This is because the overhead of checking for socket readiness using isReady grows proportionally to the total number of sockets. When using callbacks calling isReady on every socket is no longer necessary.

Because a socket can be ready for receiving, sending or both, the type of readiness is passed to the attached callback as a bitwise combination of SocketSelector::Receive and/or SocketSelector::Send when it is called by dispatchReadyCallbacks. Some systems don't support combined read and write notifications. On these systems, if a socket is ready to be both received from and sent to the callback will be called twice, once with SocketSelector::Receive and once with SocketSelector::Send.

To remove the attached callback of a socket, call add again with an empty function.

By default, no readiness callback is attached when adding a socket.

Parameters

  socket | Reference to the socket to add
  readinessType | Type of readiness to wait for, a bitwise combination of SocketSelector::Receive and/or SocketSelector::Send
  readyCallback | Ready callback to attach to the socket, pass an empty function to remove the ready callback

Returns
  true if the socket was added successfully, false otherwise

See also
  remove, clear

## ◆ clear()

void sf::SocketSelector::clear | ( |  | ) |

Remove all the sockets stored in the selector.

This function doesn't destroy any instance, it simply removes all the references that the selector has to external sockets.

See also
  add, remove

## ◆ dispatchReadyCallbacks()

void sf::SocketSelector::dispatchReadyCallbacks | ( |  | ) |

Dispatch callbacks of ready sockets.

After calling wait returns true, at least one socket is ready to receive or send data. Calling dispatchReadyCallbacks will call the attached ready callback for every socket that is ready to either receive or send data. Sockets that don't have a callback attached can still be individually checked using isReady.

The readiness state of each socket is maintained until the next call to wait. Calling dispatchReadyCallbacks multiple times after a single call to wait will run the exact same callbacks with the exact same passed arguments.

See also
  wait

## ◆ isReady()

bool sf::SocketSelector::isReady | ( | const Socket & | socket,
|  | ReadinessType | readinessType = Receive ) const
| nodiscard

Test a socket to know if it is ready to receive or send data.

This function must be used after a call to wait, to know which sockets are ready to receive or send data. If a socket is ready, a call to receive or send will never block because we know that there is data available to read or we can write. Note that if this function returns true for a TcpListener, this means that it is ready to accept a new connection.

Parameters

  socket | Socket to test
  readinessType | Type of readiness to check for, a bitwise combination of SocketSelector::Receive and/or SocketSelector::Send

Returns
  true if the socket is ready to read, false otherwise

See also
  wait

## ◆ operator=() [1/2]

SocketSelector & sf::SocketSelector::operator= | ( | const SocketSelector & | right | ) |

Overload of assignment operator.

Parameters

  right | Instance to assign

Returns
  Reference to self

## ◆ operator=() [2/2]

SocketSelector & sf::SocketSelector::operator= | ( | SocketSelector && |  | ) |
| noexcept

Move assignment.

## ◆ remove()

bool sf::SocketSelector::remove | ( | const Socket & | socket | ) |

Remove a socket from the selector.

This function doesn't destroy the socket, it simply removes the reference that the selector has to it.

Parameters

  socket | Reference to the socket to remove

Returns
  true if the socket was removed successfully, false otherwise

See also
  add, clear

## ◆ wait()

bool sf::SocketSelector::wait | ( | Time | timeout = Time::Zero | ) |
| nodiscard

Wait until one or more sockets are ready to receive or send.

This function returns as soon as at least one socket has some data available to be received or data can be sent, depending on how the socket was added to this selector. To know which sockets are ready, use the isReady function. If you use a timeout and no socket is ready before the timeout is over, the function returns false.

Parameters

  timeout | Maximum time to wait, (use Time::Zero for infinity)

Returns
  true if there are sockets ready, false otherwise

See also
  isReady, dispatchReadyCallbacks

The documentation for this class was generated from the following file:

- SocketSelector.hpp