C++ WebSocket Server Workshop
December 8, 2016 ยท View on GitHub
Part 3: Initiating messages from the server
Echoing received messages back to the client
To add functionality for sending messages to the client from the server, we add the following function to the WebsocketServer class:
void sendMessage(ClientConnection conn, const string& messageType, const Json::Value& arguments)
{
//Copy the argument values, and bundle the message type into the object
Json::Value messageData = arguments;
messageData["__MESSAGE__"] = messageType;
//Send the JSON data to the client
this->endpoint.send(conn, WebsocketServer::stringifyJson(messageData), websocketpp::frame::opcode::text);
}
We can now echo messages back to the client when we receive them, by adding the following code to the WebsocketServer::onMessage function:
this->sendMessage(conn, messageType, messageObject);
Broadcasting messages to all connected clients
At the moment, the server does not keep track of which clients are currently connected. To facilitate broadcasting messages to all clients, we need to add functionality to maintain a list of connected clients. First, we need to add the following includes:
#include <vector>
using std::vector;
We can then add a member field to the WebsocketServer class to hold the list of connections:
vector<ClientConnection> openConnections;
To update the list, we need to modify the WebsocketServer::onOpen and WebsocketServer::onClose functions to become:
void WebsocketServer::onOpen(ClientConnection conn)
{
//Add the connection handle to our list of open connections
openConnections.push_back(conn);
}
void WebsocketServer::onClose(ClientConnection conn)
{
//Remove the connection handle from our list of open connections
auto connVal = conn.lock();
auto newEnd = std::remove_if(openConnections.begin(), openConnections.end(), [&connVal](ClientConnection elem)
{
//If the pointer has expired, remove it from the vector
if (elem.expired() == true) {
return true;
}
//If the pointer is still valid, compare it to the handle for the closed connection
auto elemVal = elem.lock();
if (elemVal.get() == connVal.get()) {
return true;
}
return false;
});
//Truncate the connections vector to erase the removed elements
openConnections.resize(std::distance(openConnections.begin(), newEnd));
}
The convoluted code in WebsocketServer::onClose is required due to the use of a std::weak_ptr<void> for the connection handle type, which does not facilitate comparison with other handles without being upgraded to a std::shared_ptr instance first.
Now that we have a list of connected clients, we can easily implement functionality to broadcast messages to all of them at once:
void broadcastMessage(const string& messageType, const Json::Value& arguments)
{
for (auto conn : this->openConnections) {
this->sendMessage(conn, messageType, arguments);
}
}
We can also provide access to the size of the list, so that other code can determine the number of currently open connections:
size_t numConnections() {
return this->openConnections.size();
}