Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
quic_client_example.cpp
Go to the documentation of this file.
1
23#include <iostream>
24#include <string>
25#include <memory>
26#include <thread>
27#include <chrono>
28#include <vector>
29#include <atomic>
30#include <condition_variable>
31#include <mutex>
32
33#define NETWORK_USE_EXPERIMENTAL
35
36using namespace kcenon::network;
37
42{
43public:
44 QuicClientDemo(const std::string& server_host, unsigned short server_port)
45 : server_host_(server_host)
46 , server_port_(server_port)
47 , connected_(false)
48 , message_received_(false)
49 {
50 }
51
52 bool run()
53 {
54 std::cout << "=== QUIC Client Example ===" << std::endl;
55 std::cout << "Connecting to " << server_host_ << ":" << server_port_ << std::endl;
56
57 // Create QUIC client directly for QUIC-specific features
58 client_ = std::make_shared<core::messaging_quic_client>("quic_demo_client");
59
60 // Set up callbacks
62
63 // Start the client
65 if (result.is_err())
66 {
67 std::cerr << "Failed to start client: " << result.error().message << std::endl;
68 return false;
69 }
70
71 std::cout << "Client started, waiting for connection..." << std::endl;
72
73 // Wait for connection (with timeout)
74 {
75 std::unique_lock<std::mutex> lock(mutex_);
76 bool connected = cv_.wait_for(lock, std::chrono::seconds(10), [this]() {
77 return connected_.load();
78 });
79
80 if (!connected)
81 {
82 std::cerr << "Connection timeout" << std::endl;
83 (void)client_->stop_client();
84 return false;
85 }
86 }
87
88 std::cout << "Connected to server!" << std::endl;
89
90 // Demo: Send data on default stream
92
93 // Demo: Create and use multiple streams
95
96 // Wait a bit for responses
97 std::this_thread::sleep_for(std::chrono::seconds(2));
98
99 // Get statistics
100 auto stats = client_->stats();
101 std::cout << "\n=== Connection Statistics ===" << std::endl;
102 std::cout << "Bytes sent: " << stats.bytes_sent << std::endl;
103 std::cout << "Bytes received: " << stats.bytes_received << std::endl;
104 std::cout << "Packets sent: " << stats.packets_sent << std::endl;
105 std::cout << "Packets received: " << stats.packets_received << std::endl;
106 std::cout << "Packets lost: " << stats.packets_lost << std::endl;
107
108 // Stop the client
109 std::cout << "\nStopping client..." << std::endl;
110 (void)client_->stop_client();
112
113 std::cout << "Client stopped." << std::endl;
114 return true;
115 }
116
117private:
119 {
120 // Connected callback
122 std::cout << "[Callback] Connected to server" << std::endl;
123 connected_.store(true);
124 cv_.notify_all();
125 });
126
127 // Disconnected callback
129 std::cout << "[Callback] Disconnected from server" << std::endl;
130 connected_.store(false);
131 });
132
133 // Error callback
134 client_->set_error_callback([](std::error_code ec) {
135 std::cerr << "[Callback] Error: " << ec.message() << std::endl;
136 });
137
138 // Receive callback for default stream
139 client_->set_receive_callback([this](const std::vector<uint8_t>& data) {
140 std::string msg(data.begin(), data.end());
141 std::cout << "[Callback] Received on default stream: " << msg << std::endl;
142 message_received_.store(true);
143 });
144
145 // Stream receive callback for all streams
147 [](uint64_t stream_id, const std::vector<uint8_t>& data, bool fin) {
148 std::string msg(data.begin(), data.end());
149 std::cout << "[Callback] Stream " << stream_id << ": "
150 << data.size() << " bytes"
151 << (fin ? " (FIN)" : "") << std::endl;
152 std::cout << " Data: " << msg << std::endl;
153 });
154 }
155
157 {
158 std::cout << "\n=== Sending on Default Stream ===" << std::endl;
159
160 // Send string data
161 auto result = client_->send_packet("Hello, QUIC Server!");
162 if (result.is_ok())
163 {
164 std::cout << "Sent string message on default stream" << std::endl;
165 }
166 else
167 {
168 std::cerr << "Failed to send: " << result.error().message << std::endl;
169 }
170
171 // Send binary data
172 std::vector<uint8_t> binary_data = {0x01, 0x02, 0x03, 0x04, 0x05};
173 result = client_->send_packet(std::move(binary_data));
174 if (result.is_ok())
175 {
176 std::cout << "Sent binary data on default stream" << std::endl;
177 }
178 else
179 {
180 std::cerr << "Failed to send: " << result.error().message << std::endl;
181 }
182 }
183
185 {
186 std::cout << "\n=== Multi-Stream Demo ===" << std::endl;
187
188 // Create a new bidirectional stream
189 auto stream_result = client_->create_stream();
190 if (stream_result.is_err())
191 {
192 std::cerr << "Failed to create stream: " << stream_result.error().message << std::endl;
193 return;
194 }
195
196 uint64_t stream_id = stream_result.value();
197 std::cout << "Created bidirectional stream: " << stream_id << std::endl;
198
199 // Send data on the new stream
200 std::string msg = "Hello from stream " + std::to_string(stream_id);
201 std::vector<uint8_t> data(msg.begin(), msg.end());
202
203 auto send_result = client_->send_on_stream(stream_id, std::move(data));
204 if (send_result.is_ok())
205 {
206 std::cout << "Sent message on stream " << stream_id << std::endl;
207 }
208 else
209 {
210 std::cerr << "Failed to send: " << send_result.error().message << std::endl;
211 }
212
213 // Create a unidirectional stream
214 auto uni_stream_result = client_->create_unidirectional_stream();
215 if (uni_stream_result.is_ok())
216 {
217 uint64_t uni_stream_id = uni_stream_result.value();
218 std::cout << "Created unidirectional stream: " << uni_stream_id << std::endl;
219
220 std::string uni_msg = "Unidirectional message";
221 std::vector<uint8_t> uni_data(uni_msg.begin(), uni_msg.end());
222
223 // Send with FIN to close the stream after this message
224 auto uni_send_result = client_->send_on_stream(uni_stream_id,
225 std::move(uni_data),
226 true /* fin */);
227 if (uni_send_result.is_ok())
228 {
229 std::cout << "Sent message on unidirectional stream with FIN" << std::endl;
230 }
231 }
232
233 // Close the bidirectional stream
234 auto close_result = client_->close_stream(stream_id);
235 if (close_result.is_ok())
236 {
237 std::cout << "Closed stream " << stream_id << std::endl;
238 }
239 }
240
241 std::string server_host_;
242 unsigned short server_port_;
243 std::shared_ptr<core::messaging_quic_client> client_;
244 std::atomic<bool> connected_;
245 std::atomic<bool> message_received_;
246 std::mutex mutex_;
247 std::condition_variable cv_;
248};
249
254{
255 std::cout << "\n=== QUIC Client with Custom Config ===" << std::endl;
256
257 // Create client directly for QUIC-specific features
258 auto client = std::make_shared<core::messaging_quic_client>("config_demo_client");
259
260 // Configure QUIC-specific options
262 config.verify_server = false; // For testing with self-signed certs
263 config.alpn_protocols = {"h3"};
264 config.max_idle_timeout_ms = 60000; // 60 seconds
265 config.enable_early_data = true; // Enable 0-RTT
266
267 // For mutual TLS, set optional fields:
268 // config.ca_cert_file = "/path/to/ca.pem";
269 // config.client_cert_file = "/path/to/client.pem";
270 // config.client_key_file = "/path/to/client-key.pem";
271
272 auto result = client->start_client("example.com", 443, config);
273 if (result.is_err())
274 {
275 std::cout << "Expected failure (no server): " << result.error().message << std::endl;
276 }
277
278 (void)client->stop_client();
279}
280
281int main(int argc, char* argv[])
282{
283 std::string host = "127.0.0.1";
284 unsigned short port = 4433;
285
286 if (argc >= 2)
287 {
288 host = argv[1];
289 }
290 if (argc >= 3)
291 {
292 port = static_cast<unsigned short>(std::stoi(argv[2]));
293 }
294
295 // Run the main demo
296 QuicClientDemo demo(host, port);
297
298 // Note: This will likely fail without a running QUIC server
299 // The demo is primarily to show the API usage
300 std::cout << "\nNote: This demo requires a running QUIC server." << std::endl;
301 std::cout << "Without a server, connection will timeout." << std::endl;
302 std::cout << std::endl;
303
304 bool success = demo.run();
305
306 // Also show configuration example
308
309 return success ? 0 : 1;
310}
int main()
Simple QUIC client demo.
std::shared_ptr< core::messaging_quic_client > client_
unsigned short server_port_
QuicClientDemo(const std::string &server_host, unsigned short server_port)
std::condition_variable cv_
std::atomic< bool > message_received_
std::atomic< bool > connected_
auto set_disconnected_callback(interfaces::i_quic_client::disconnected_callback_t callback) -> void override
Sets the callback for disconnection (interface version).
auto wait_for_stop() -> void override
Blocks until stop() is called.
auto create_unidirectional_stream() -> Result< uint64_t > override
Creates a new unidirectional stream (interface version).
auto start_client(std::string_view host, unsigned short port) -> VoidResult
Starts the client with default configuration.
auto close_stream(uint64_t stream_id) -> VoidResult override
Closes a stream (interface version).
auto send_on_stream(uint64_t stream_id, std::vector< uint8_t > &&data, bool fin=false) -> VoidResult override
Sends data on a specific stream (interface version).
auto set_receive_callback(interfaces::i_quic_client::receive_callback_t callback) -> void override
Sets the callback for received data on default stream (interface version).
auto send_packet(std::vector< uint8_t > &&data) -> VoidResult
Send data on the default stream (stream 0).
auto stop_client() -> VoidResult
Stops the client and releases all resources.
auto create_stream() -> Result< uint64_t > override
Creates a new bidirectional stream (interface version).
auto set_connected_callback(interfaces::i_quic_client::connected_callback_t callback) -> void override
Sets the callback for connection established (interface version).
auto set_stream_receive_callback(stream_receive_callback_t callback) -> void
Sets the callback for stream data reception (all streams, legacy version).
auto stats() const -> quic_connection_stats
Get connection statistics.
auto set_error_callback(interfaces::i_quic_client::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 demo_with_config()
Example with custom configuration.
Configuration options for QUIC client.
Definition quic_client.h:51