Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
quic_server_example.cpp
Go to the documentation of this file.
1
24// Enable experimental QUIC API
25#ifndef NETWORK_USE_EXPERIMENTAL
26#define NETWORK_USE_EXPERIMENTAL
27#endif
28
31
32#include <iostream>
33#include <string>
34#include <memory>
35#include <thread>
36#include <chrono>
37#include <vector>
38#include <atomic>
39#include <signal.h>
40
41using namespace kcenon::network;
42using namespace kcenon::network::session;
43
44// Global flag for graceful shutdown
45std::atomic<bool> g_running{true};
46
48{
49 std::cout << "\nShutdown signal received..." << std::endl;
50 g_running.store(false);
51}
52
57{
58public:
59 explicit QuicServerDemo(unsigned short port)
60 : port_(port)
61 {
62 }
63
64 bool run()
65 {
66 std::cout << "=== QUIC Server Example ===" << std::endl;
67 std::cout << "Starting server on port " << port_ << std::endl;
68
69 // Create QUIC server directly for QUIC-specific features
70 server_ = std::make_shared<core::messaging_quic_server>("quic_demo_server");
71
72 // Set up callbacks
74
75 // Create configuration for start_server
77 config.max_idle_timeout_ms = 30000;
78 config.max_connections = 100;
79 config.alpn_protocols = {"h3", "hq-interop"};
80
81 // Start the server
82 auto result = server_->start_server(port_, config);
83 if (result.is_err())
84 {
85 std::cerr << "Failed to start server: " << result.error().message
86 << std::endl;
87 return false;
88 }
89
90 std::cout << "Server started successfully!" << std::endl;
91 std::cout << "Press Ctrl+C to stop the server..." << std::endl;
92 std::cout << std::endl;
93
94 // Main loop - print statistics periodically
95 while (g_running.load())
96 {
97 std::this_thread::sleep_for(std::chrono::seconds(5));
98
99 if (g_running.load())
100 {
101 print_status();
102 }
103 }
104
105 // Graceful shutdown
106 std::cout << "\n=== Shutting Down ===" << std::endl;
107
108 // Disconnect all clients
109 std::cout << "Disconnecting " << server_->session_count()
110 << " clients..." << std::endl;
112
113 // Stop the server
114 std::cout << "Stopping server..." << std::endl;
115 (void)server_->stop_server();
117
118 std::cout << "Server stopped." << std::endl;
119 return true;
120 }
121
122private:
124 {
125 // Connection callback - called when a new client connects
127 [](std::shared_ptr<quic_session> session)
128 {
129 std::cout << "[Connect] New client: " << session->session_id()
130 << " from " << session->remote_endpoint().address()
131 << std::endl;
132
133 // Send welcome message
134 std::string welcome = "Welcome to QUIC server!";
135 auto result = session->send(
136 std::vector<uint8_t>(welcome.begin(), welcome.end()));
137 if (result.is_err())
138 {
139 std::cerr << " Failed to send welcome: "
140 << result.error().message << std::endl;
141 }
142 });
143
144 // Disconnection callback - called when a client disconnects
146 [](std::shared_ptr<quic_session> session)
147 {
148 std::cout << "[Disconnect] Client left: "
149 << session->session_id() << std::endl;
150 });
151
152 // Receive callback - called when data is received
154 [this](std::shared_ptr<quic_session> session,
155 const std::vector<uint8_t>& data)
156 {
157 std::string msg(data.begin(), data.end());
158 std::cout << "[Receive] From " << session->session_id() << ": "
159 << msg << std::endl;
160
161 // Echo the message back
162 std::string response = "Echo: " + msg;
163 auto result = session->send(
164 std::vector<uint8_t>(response.begin(), response.end()));
165 if (result.is_err())
166 {
167 std::cerr << " Failed to echo: " << result.error().message
168 << std::endl;
169 }
170
171 // Handle special commands
172 handle_command(session, msg);
173 });
174
175 // Stream receive callback - called for stream-specific data
177 [](std::shared_ptr<quic_session> session,
178 uint64_t stream_id,
179 const std::vector<uint8_t>& data,
180 bool fin)
181 {
182 std::cout << "[Stream] From " << session->session_id()
183 << " on stream " << stream_id << ": "
184 << data.size() << " bytes"
185 << (fin ? " (FIN)" : "") << std::endl;
186 });
187
188 // Error callback
190 [](std::error_code ec)
191 {
192 std::cerr << "[Error] Server error: " << ec.message()
193 << std::endl;
194 });
195 }
196
197 void handle_command(std::shared_ptr<quic_session> session,
198 const std::string& msg)
199 {
200 if (msg == "/status")
201 {
202 // Send server status
203 std::string status = "Server status: " +
204 std::to_string(server_->session_count()) +
205 " clients connected";
206 (void)session->send(
207 std::vector<uint8_t>(status.begin(), status.end()));
208 }
209 else if (msg == "/broadcast")
210 {
211 // Broadcast to all clients
213 }
214 else if (msg.substr(0, 5) == "/list")
215 {
216 // List all connected clients
217 std::string list = "Connected clients:\n";
218 for (const auto& s : server_->sessions())
219 {
220 list += " - " + s->session_id() + "\n";
221 }
222 (void)session->send(std::vector<uint8_t>(list.begin(), list.end()));
223 }
224 }
225
227 {
228 std::cout << "\n=== Broadcasting to All Clients ===" << std::endl;
229
230 std::string broadcast_msg = "Broadcast: Hello everyone!";
231 auto result = server_->broadcast(
232 std::vector<uint8_t>(broadcast_msg.begin(), broadcast_msg.end()));
233
234 if (result.is_ok())
235 {
236 std::cout << "Broadcast sent to " << server_->session_count()
237 << " clients" << std::endl;
238 }
239 else
240 {
241 std::cerr << "Broadcast failed: " << result.error().message
242 << std::endl;
243 }
244 }
245
247 {
248 std::cout << "\n--- Server Status ---" << std::endl;
249 std::cout << "Running: " << (server_->is_running() ? "Yes" : "No")
250 << std::endl;
251 std::cout << "Connected clients: " << server_->session_count()
252 << std::endl;
253
254 auto sessions = server_->sessions();
255 if (!sessions.empty())
256 {
257 std::cout << "Sessions:" << std::endl;
258 for (const auto& session : sessions)
259 {
260 if (session && session->is_active())
261 {
262 auto stats = session->stats();
263 std::cout << " " << session->session_id()
264 << " - Bytes: sent=" << stats.bytes_sent
265 << ", recv=" << stats.bytes_received << std::endl;
266 }
267 }
268 }
269 std::cout << "---------------------" << std::endl;
270 }
271
272 unsigned short port_;
273 std::shared_ptr<core::messaging_quic_server> server_;
274};
275
279void demo_multicast(std::shared_ptr<core::messaging_quic_server> server)
280{
281 std::cout << "\n=== Multicast Demo ===" << std::endl;
282
283 auto sessions = server->sessions();
284 if (sessions.size() < 2)
285 {
286 std::cout << "Need at least 2 clients for multicast demo" << std::endl;
287 return;
288 }
289
290 // Get first two session IDs
291 std::vector<std::string> target_ids;
292 target_ids.push_back(sessions[0]->session_id());
293 target_ids.push_back(sessions[1]->session_id());
294
295 std::string multicast_msg = "Multicast: Selected clients only!";
296 auto result = server->multicast(
297 target_ids,
298 std::vector<uint8_t>(multicast_msg.begin(), multicast_msg.end()));
299
300 if (result.is_ok())
301 {
302 std::cout << "Multicast sent to " << target_ids.size() << " clients"
303 << std::endl;
304 }
305 else
306 {
307 std::cerr << "Multicast failed: " << result.error().message
308 << std::endl;
309 }
310}
311
316{
317 std::cout << "\n=== Simple QUIC Server ===" << std::endl;
318
319 // Create server directly for QUIC-specific features
320 auto server = std::make_shared<core::messaging_quic_server>("simple_server");
321
322 // Minimal setup - just echo received messages
323 server->set_receive_callback(
324 [](std::shared_ptr<quic_session> session,
325 const std::vector<uint8_t>& data)
326 {
327 // Echo back
328 std::vector<uint8_t> response(data);
329 (void)session->send(std::move(response));
330 });
331
333 config.cert_file = "/path/to/server.crt";
334 config.key_file = "/path/to/server.key";
335
336 auto result = server->start_server(4434, config);
337 if (result.is_ok())
338 {
339 std::cout << "Simple server started on port 4434" << std::endl;
340 std::this_thread::sleep_for(std::chrono::seconds(5));
341 (void)server->stop_server();
342 }
343}
344
345int main(int argc, char* argv[])
346{
347 // Set up signal handler for graceful shutdown
348 signal(SIGINT, signal_handler);
349 signal(SIGTERM, signal_handler);
350
351 unsigned short port = 4433;
352
353 if (argc >= 2)
354 {
355 port = static_cast<unsigned short>(std::stoi(argv[1]));
356 }
357
358 std::cout << "QUIC Server Example" << std::endl;
359 std::cout << "===================" << std::endl;
360 std::cout << std::endl;
361
362 // Run the main demo
363 QuicServerDemo demo(port);
364 bool success = demo.run();
365
366 return success ? 0 : 1;
367}
int main()
Simple QUIC server demo.
std::shared_ptr< core::messaging_quic_server > server_
QuicServerDemo(unsigned short port)
void handle_command(std::shared_ptr< quic_session > session, const std::string &msg)
auto is_running() const -> bool override
Checks if the server is currently running.
auto stop_server() -> VoidResult
Stops the server and releases all resources.
auto disconnect_all(uint64_t error_code=0) -> void
Disconnect all active sessions.
auto sessions() const -> std::vector< std::shared_ptr< session::quic_session > >
Get all active sessions.
auto broadcast(std::vector< uint8_t > &&data) -> VoidResult
Send data to all connected clients.
auto set_stream_receive_callback(stream_receive_callback_t callback) -> void
Sets the callback for stream data reception (legacy version).
auto set_receive_callback(interfaces::i_quic_server::receive_callback_t callback) -> void override
Sets the callback for received data on default stream (interface version).
auto set_connection_callback(interfaces::i_quic_server::connection_callback_t callback) -> void override
Sets the callback for new connections (interface version).
auto session_count() const -> size_t
Get the number of active sessions.
auto start_server(unsigned short port) -> VoidResult
Start the server with default configuration.
auto wait_for_stop() -> void override
Blocks until stop() is called.
auto set_disconnection_callback(interfaces::i_quic_server::disconnection_callback_t callback) -> void override
Sets the callback for disconnections (interface version).
auto set_error_callback(interfaces::i_quic_server::error_callback_t callback) -> void override
Sets the callback for errors (interface version).
tracing_config config
Definition exporters.cpp:29
Main namespace for all Network System components.
void simple_server_example()
Example with minimal setup.
void demo_multicast(std::shared_ptr< core::messaging_quic_server > server)
Example showing multicast functionality.
void signal_handler(int)
std::atomic< bool > g_running
QUIC-specific session with stream multiplexing.
Configuration options for QUIC server.
Definition quic_server.h:70