A modern, high-performance C++ client for Socket.IO with C++20 coroutine support, comprehensive error handling, and production-ready features.
- Modern C++20 - Coroutine support with async/await
- Thread-Safe - Concurrent listener management without crashes
- Smart Pointers - Automatic memory management, no leaks
- Binary Support - Send/receive binary data efficiently
- Auto JSON Encoding - Seamless JSON serialization
- Namespace Support - Multiple namespaces on single connection
- Disconnect Tracking - Detailed reason codes for troubleshooting
- Flexible Reconnection - Configurable exponential backoff
- Cross-Platform - iOS, Android, macOS, Linux, Windows
| C++ Client version | Socket.IO server version | |
|---|---|---|
| 1.x / 2.x | 3.x / 4.x | |
2.x (2.x branch) |
YES | YES, with allowEIO3: true |
3.x (master branch) |
NO | YES |
# Clone with submodules
git clone --recurse-submodules https://github.com/yourusername/socket.io-client-cpp.git
cd socket.io-client-cpp
# Build
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make
sudo make install#include "sio_client.h"
int main() {
sio::client client;
// Connect
client.connect("http://localhost:3000");
// Listen for events
client.socket()->on("welcome", [](sio::event& ev) {
std::cout << "Message: " << ev.get_message()->get_string() << std::endl;
});
// Emit events
client.socket()->emit("hello", sio::string_message::create("world"));
// Keep running
std::this_thread::sleep_for(std::chrono::seconds(10));
client.sync_close();
return 0;
}- Installation
- API Overview
- C++20 Coroutines
- Disconnect Handling
- Advanced Features
- Build Configuration
- Examples
Managed via git submodules:
- ASIO 1.36.0
- SimdJSON 3.10.1
- WebSocket++ 0.8.2
- OpenSSL (system, Release builds only)
cmake -DCMAKE_BUILD_TYPE=Debug ..
make- Protocol:
ws://(WebSocket) - Size: ~24MB (with debug symbols)
- Use for: Local development
cmake -DCMAKE_BUILD_TYPE=Release ..
make- Protocol:
wss://(WebSocket Secure) - Size: ~2.7MB (optimized)
- Use for: Production deployments
sio::client client;
// Simple connect
client.connect("http://localhost:3000");
// With authentication
auto auth = sio::object_message::create();
auth->get_map()["token"] = sio::string_message::create("secret");
client.connect("http://localhost:3000", auth);
// With query parameters
std::map<std::string, std::string> query{{"version", "1.0"}};
client.connect("http://localhost:3000", query);// Lambda
client.socket()->on("message", [](sio::event& ev) {
auto msg = ev.get_message();
std::cout << msg->get_string() << std::endl;
});
// Function pointer
void onConnect(sio::event& ev) { /* ... */ }
client.socket()->on("connect", &onConnect);
// Catch-all listener
client.socket()->on_any([](sio::event& ev) {
std::cout << "Event: " << ev.get_name() << std::endl;
});// Simple emit
client.socket()->emit("ping");
// With data
client.socket()->emit("message", sio::string_message::create("Hello"));
// With acknowledgment callback
client.socket()->emit_with_ack("request", data, [](sio::message::list const& response) {
std::cout << "Got response" << std::endl;
});
// With timeout
client.socket()->emit_with_ack("request", data,
[](auto& response) { /* success */ },
5000, // timeout in ms
[]() { std::cerr << "Timeout!" << std::endl; }
);// Simplified handler that provides ack_message directly
client.socket()->on_with_ack("request", [](sio::message::ptr const& msg, sio::message::list& ack_msg) {
// Process request
auto value = msg->get_int();
// Send acknowledgment
ack_msg.push(sio::string_message::create("Success"));
ack_msg.push(sio::int_message::create(value * 2));
});Avoid callback hell with modern async/await syntax.
- C++20 compiler (GCC 10+, Clang 14+, MSVC 2019 16.8+)
- CMake 3.12+
#include "sio_client.h"
sio::emit_task async_operation(sio::socket::ptr socket) {
// Sequential async operations - no nested callbacks!
auto auth = co_await socket->emit_async("login", credentials);
auto data = co_await socket->emit_async("getData", auth);
auto result = co_await socket->emit_async("process", data);
std::cout << "Done!" << std::endl;
co_return result;
}
int main() {
sio::client client;
client.connect("http://localhost:3000");
// Start the coroutine
async_operation(client.socket());
// Keep running
std::this_thread::sleep_for(std::chrono::seconds(10));
return 0;
}sio::emit_task with_timeout(sio::socket::ptr socket) {
try {
// 5 second timeout
auto response = co_await socket->emit_async("slowOp", params, 5000);
std::cout << "Success!" << std::endl;
co_return response;
} catch (const sio::timeout_exception& e) {
std::cerr << "Operation timed out" << std::endl;
co_return sio::message::list();
}
}Before (Callback Hell):
socket->emit_with_ack("step1", data1, [socket](auto& r1) {
socket->emit_with_ack("step2", r1, [socket](auto& r2) {
socket->emit_with_ack("step3", r2, [](auto& r3) {
// Finally done!
});
});
});After (Clean Coroutines):
sio::emit_task workflow(sio::socket::ptr socket) {
auto r1 = co_await socket->emit_async("step1", data1);
auto r2 = co_await socket->emit_async("step2", r1);
auto r3 = co_await socket->emit_async("step3", r2);
co_return r3;
}See examples/Console/coroutine_example.cpp for a complete example.
Track exactly why connections are lost for better error handling and recovery.
enum class disconnect_reason {
client_disconnect, // User called close()
server_disconnect, // Server closed connection
transport_close, // WebSocket closed cleanly
transport_error, // Network/protocol error
ping_timeout, // Server not responding to pings
namespace_disconnect, // Namespace-specific disconnect
max_reconnect_attempts // Gave up reconnecting
};client.set_close_listener([](sio::client::disconnect_reason reason) {
switch(reason) {
case sio::client::disconnect_reason::ping_timeout:
std::cout << "Server stopped responding" << std::endl;
// Maybe increase ping timeout or alert monitoring
break;
case sio::client::disconnect_reason::transport_error:
std::cout << "Network error" << std::endl;
// Check connectivity, maybe retry with different network
break;
case sio::client::disconnect_reason::max_reconnect_attempts:
std::cout << "Could not reconnect after multiple attempts" << std::endl;
// Show offline mode, notify user
break;
case sio::client::disconnect_reason::server_disconnect:
std::cout << "Server closed connection (kicked or shutdown)" << std::endl;
break;
default:
std::cout << "Disconnected" << std::endl;
break;
}
});class SmartClient {
sio::client client_;
std::atomic<int> ping_timeout_count_{0};
public:
SmartClient() {
client_.set_close_listener([this](sio::client::disconnect_reason reason) {
if (reason == sio::client::disconnect_reason::ping_timeout) {
ping_timeout_count_++;
if (ping_timeout_count_ >= 3) {
std::cout << "Multiple ping timeouts - server may be down" << std::endl;
// Try different server or notify ops team
}
}
});
client_.set_open_listener([this]() {
ping_timeout_count_ = 0; // Reset on success
});
}
};// Configure all parameters at once
sio::reconnect_config config(
10, // max attempts
2000, // initial delay (2s)
10000 // max delay (10s)
);
client.set_reconnect_config(config);
// Or use presets
client.set_reconnect_config(sio::reconnect_config::disabled());client.set_state_listener([](sio::client::connection_state state) {
switch(state) {
case sio::client::connection_state::connecting:
std::cout << "Connecting..." << std::endl;
break;
case sio::client::connection_state::connected:
std::cout << "Connected!" << std::endl;
break;
case sio::client::connection_state::reconnecting:
std::cout << "Reconnecting..." << std::endl;
break;
case sio::client::connection_state::disconnected:
std::cout << "Disconnected" << std::endl;
break;
}
});// Default namespace
auto default_socket = client.socket();
// Custom namespace
auto chat = client.socket("/chat");
auto admin = client.socket("/admin");
// Use them independently
chat->emit("message", sio::string_message::create("Hello"));
admin->emit("command", sio::string_message::create("status"));// All operations are thread-safe
std::thread t1([&]() { socket->on("event1", handler1); });
std::thread t2([&]() { socket->on("event2", handler2); });
std::thread t3([&]() { socket->off("event1"); });
// All will execute safely without crashes
t1.join();
t2.join();
t3.join();auto metrics = socket->get_metrics();
std::cout << "Packets sent: " << metrics.packets_sent << std::endl;
std::cout << "Packets received: " << metrics.packets_received << std::endl;
std::cout << "Ping latency: " << metrics.last_ping_latency.count() << "ms" << std::endl;// Share io_context with your application
asio::io_context io_context;
sio::client_options opts;
opts.io_context = &io_context;
sio::client client(opts);
client.connect("http://localhost:3000");
// Run in your event loop
io_context.run();// Enable all logs
client.set_logs_verbose();
// Quiet mode (errors only)
client.set_logs_quiet();
// Default (connection events + errors)
client.set_logs_default();- Console Chat - Basic CLI chat client
- C++20 Coroutines - Modern async/await
- QT Chat - GUI application
- iOS Chat - Mobile application
- ✅ Replaced
std::bindwith lambdas (2-5% faster event dispatch) - ✅ Optimized string handling with move semantics
- ✅ Improved async I/O with modern ASIO patterns
- ✅ Atomic state management for lock-free operations
- ✅ C++20 coroutine support with
emit_async() - ✅ Detailed disconnect reason tracking
- ✅ Auto-acknowledgment with
on_with_ack() - ✅ Catch-all listener with
on_any() - ✅ Connection state observer
- ✅ Flexible reconnection configuration
- ✅ Connection metrics and monitoring
- ✅ Fixed memory leaks in event listeners
- ✅ Thread-safe listener operations
- ✅ Smart pointer management (no manual delete)
- ✅ Comprehensive unit tests for thread safety
- ✅ Zero compilation warnings
- ✅ ASIO: 1.10.2 → 1.36.0
- ✅ JSON Parser: RapidJSON → SimdJSON 3.10.1 (much faster)
- ✅ WebSocket++: Updated to 0.8.2
- API Reference - Complete API documentation
- Installation Guide - Detailed build instructions
- iOS Setup - iOS-specific instructions
- Compression Analysis - Performance considerations
Contributions are welcome! Please feel free to submit a Pull Request.
MIT License - see LICENSE for details.
- GitHub Issues: Report bugs or request features
- Stack Overflow: Tag with
socket.ioandc++
