CppServer 1.0.5.0
C++ Server Library
Loading...
Searching...
No Matches
tcp_client.cpp
Go to the documentation of this file.
1
10
11namespace CppServer {
12namespace Asio {
13
14TCPClient::TCPClient(const std::shared_ptr<Service>& service, const std::string& address, int port)
15 : _id(CppCommon::UUID::Sequential()),
16 _service(service),
17 _io_service(_service->GetAsioService()),
18 _strand(*_io_service),
19 _strand_required(_service->IsStrandRequired()),
20 _address(address),
21 _port(port),
22 _socket(*_io_service),
23 _resolving(false),
24 _connecting(false),
25 _connected(false),
26 _bytes_pending(0),
27 _bytes_sending(0),
28 _bytes_sent(0),
29 _bytes_received(0),
30 _receiving(false),
31 _sending(false),
32 _send_buffer_flush_offset(0),
33 _option_keep_alive(false),
34 _option_no_delay(false)
35{
36 assert((service != nullptr) && "Asio service is invalid!");
37 if (service == nullptr)
38 throw CppCommon::ArgumentException("Asio service is invalid!");
39}
40
41TCPClient::TCPClient(const std::shared_ptr<Service>& service, const std::string& address, const std::string& scheme)
42 : _id(CppCommon::UUID::Sequential()),
43 _service(service),
44 _io_service(_service->GetAsioService()),
45 _strand(*_io_service),
46 _strand_required(_service->IsStrandRequired()),
47 _address(address),
48 _scheme(scheme),
49 _port(0),
50 _socket(*_io_service),
51 _resolving(false),
52 _connecting(false),
53 _connected(false),
54 _bytes_pending(0),
55 _bytes_sending(0),
56 _bytes_sent(0),
57 _bytes_received(0),
58 _receiving(false),
59 _sending(false),
60 _send_buffer_flush_offset(0),
61 _option_keep_alive(false),
62 _option_no_delay(false)
63{
64 assert((service != nullptr) && "Asio service is invalid!");
65 if (service == nullptr)
66 throw CppCommon::ArgumentException("Asio service is invalid!");
67}
68
69TCPClient::TCPClient(const std::shared_ptr<Service>& service, const asio::ip::tcp::endpoint& endpoint)
70 : _id(CppCommon::UUID::Sequential()),
71 _service(service),
72 _io_service(_service->GetAsioService()),
73 _strand(*_io_service),
74 _strand_required(_service->IsStrandRequired()),
75 _address(endpoint.address().to_string()),
76 _port(endpoint.port()),
77 _endpoint(endpoint),
78 _socket(*_io_service),
79 _resolving(false),
80 _connecting(false),
81 _connected(false),
82 _bytes_pending(0),
83 _bytes_sending(0),
84 _bytes_sent(0),
85 _bytes_received(0),
86 _receiving(false),
87 _sending(false),
88 _send_buffer_flush_offset(0),
89 _option_keep_alive(false),
90 _option_no_delay(false)
91{
92 assert((service != nullptr) && "Asio service is invalid!");
93 if (service == nullptr)
94 throw CppCommon::ArgumentException("Asio service is invalid!");
95}
96
98{
99 asio::socket_base::receive_buffer_size option;
100 _socket.get_option(option);
101 return option.value();
102}
103
105{
106 asio::socket_base::send_buffer_size option;
107 _socket.get_option(option);
108 return option.value();
109}
110
112{
113 asio::socket_base::receive_buffer_size option((int)size);
114 _socket.set_option(option);
115}
116
118{
119 asio::socket_base::send_buffer_size option((int)size);
120 _socket.set_option(option);
121}
122
124{
125 if (IsConnected())
126 return false;
127
128 asio::error_code ec;
129
130 // Create the server endpoint
131 _endpoint = asio::ip::tcp::endpoint(asio::ip::make_address(_address), (unsigned short)_port);
132
133 // Connect to the server
134 _socket.connect(_endpoint, ec);
135
136 // Disconnect on error
137 if (ec)
138 {
139 SendError(ec);
140
141 // Call the client disconnected handler
143
144 return false;
145 }
146
147 // Apply the option: keep alive
148 if (option_keep_alive())
149 _socket.set_option(asio::ip::tcp::socket::keep_alive(true));
150 // Apply the option: no delay
151 if (option_no_delay())
152 _socket.set_option(asio::ip::tcp::no_delay(true));
153
154 // Prepare receive & send buffers
155 _receive_buffer.resize(option_receive_buffer_size());
156 _send_buffer_main.reserve(option_send_buffer_size());
157 _send_buffer_flush.reserve(option_send_buffer_size());
158
159 // Reset statistic
160 _bytes_pending = 0;
161 _bytes_sending = 0;
162 _bytes_sent = 0;
163 _bytes_received = 0;
164
165 // Update the connected flag
166 _connected = true;
167
168 // Call the client connected handler
169 onConnected();
170
171 // Call the empty send buffer handler
172 if (_send_buffer_main.empty())
173 onEmpty();
174
175 return true;
176}
177
178bool TCPClient::Connect(const std::shared_ptr<TCPResolver>& resolver)
179{
180 if (IsConnected())
181 return false;
182
183 asio::error_code ec;
184
185 // Resolve the server endpoint
186 asio::ip::tcp::resolver::query query(_address, (_scheme.empty() ? std::to_string(_port) : _scheme));
187 auto endpoints = resolver->resolver().resolve(query, ec);
188
189 // Disconnect on error
190 if (ec)
191 {
192 SendError(ec);
193
194 // Call the client disconnected handler
196
197 return false;
198 }
199
200 // Connect to the server
201 _endpoint = asio::connect(_socket, endpoints, ec);
202
203 // Disconnect on error
204 if (ec)
205 {
206 SendError(ec);
207
208 // Call the client disconnected handler
210
211 return false;
212 }
213
214 // Apply the option: keep alive
215 if (option_keep_alive())
216 _socket.set_option(asio::ip::tcp::socket::keep_alive(true));
217 // Apply the option: no delay
218 if (option_no_delay())
219 _socket.set_option(asio::ip::tcp::no_delay(true));
220
221 // Prepare receive & send buffers
222 _receive_buffer.resize(option_receive_buffer_size());
223 _send_buffer_main.reserve(option_send_buffer_size());
224 _send_buffer_flush.reserve(option_send_buffer_size());
225
226 // Reset statistic
227 _bytes_pending = 0;
228 _bytes_sending = 0;
229 _bytes_sent = 0;
230 _bytes_received = 0;
231
232 // Update the connected flag
233 _connected = true;
234
235 // Call the client connected handler
236 onConnected();
237
238 // Call the empty send buffer handler
239 if (_send_buffer_main.empty())
240 onEmpty();
241
242 return true;
243}
244
245bool TCPClient::DisconnectInternal()
246{
247 if (!IsConnected())
248 return false;
249
250 // Close the client socket
251 _socket.close();
252
253 // Update the connected flag
254 _resolving = false;
255 _connecting = false;
256 _connected = false;
257
258 // Update sending/receiving flags
259 _receiving = false;
260 _sending = false;
261
262 // Clear send/receive buffers
263 ClearBuffers();
264
265 // Call the client disconnected handler
267
268 return true;
269}
270
272{
273 if (!Disconnect())
274 return false;
275
276 return Connect();
277}
278
280{
281 if (IsConnected() || _resolving || _connecting)
282 return false;
283
284 // Post the connect handler
285 auto self(this->shared_from_this());
286 auto connect_handler = [this, self]()
287 {
288 if (IsConnected() || _resolving || _connecting)
289 return;
290
291 // Async connect with the connect handler
292 _connecting = true;
293 auto async_connect_handler = [this, self](std::error_code ec)
294 {
295 _connecting = false;
296
297 if (IsConnected() || _resolving || _connecting)
298 return;
299
300 if (!ec)
301 {
302 // Apply the option: keep alive
303 if (option_keep_alive())
304 _socket.set_option(asio::ip::tcp::socket::keep_alive(true));
305 // Apply the option: no delay
306 if (option_no_delay())
307 _socket.set_option(asio::ip::tcp::no_delay(true));
308
309 // Prepare receive & send buffers
310 _receive_buffer.resize(option_receive_buffer_size());
311 _send_buffer_main.reserve(option_send_buffer_size());
312 _send_buffer_flush.reserve(option_send_buffer_size());
313
314 // Reset statistic
315 _bytes_pending = 0;
316 _bytes_sending = 0;
317 _bytes_sent = 0;
318 _bytes_received = 0;
319
320 // Update the connected flag
321 _connected = true;
322
323 // Try to receive something from the server
324 TryReceive();
325
326 // Call the client connected handler
327 onConnected();
328
329 // Call the empty send buffer handler
330 if (_send_buffer_main.empty())
331 onEmpty();
332 }
333 else
334 {
335 SendError(ec);
336
337 // Call the client disconnected handler
339 }
340 };
341
342 // Create the server endpoint
343 _endpoint = asio::ip::tcp::endpoint(asio::ip::make_address(_address), (unsigned short)_port);
344
345 if (_strand_required)
346 _socket.async_connect(_endpoint, bind_executor(_strand, async_connect_handler));
347 else
348 _socket.async_connect(_endpoint, async_connect_handler);
349 };
350 if (_strand_required)
351 _strand.post(connect_handler);
352 else
353 _io_service->post(connect_handler);
354
355 return true;
356}
357
358bool TCPClient::ConnectAsync(const std::shared_ptr<TCPResolver>& resolver)
359{
360 if (IsConnected() || _resolving || _connecting)
361 return false;
362
363 // Post the connect handler
364 auto self(this->shared_from_this());
365 auto connect_handler = [this, self, resolver]()
366 {
367 if (IsConnected() || _resolving || _connecting)
368 return;
369
370 // Async resolve with the connect handler
371 _resolving = true;
372 auto async_resolve_handler = [this, self](std::error_code ec1, asio::ip::tcp::resolver::results_type endpoints)
373 {
374 _resolving = false;
375
376 if (IsConnected() || _resolving || _connecting)
377 return;
378
379 if (!ec1)
380 {
381 // Async connect with the connect handler
382 _connecting = true;
383 auto async_connect_handler = [this, self](std::error_code ec2, const asio::ip::tcp::endpoint& endpoint)
384 {
385 _connecting = false;
386
387 if (IsConnected() || _resolving || _connecting)
388 return;
389
390 if (!ec2)
391 {
392 // Connect to the server
393 _endpoint = endpoint;
394
395 // Apply the option: keep alive
396 if (option_keep_alive())
397 _socket.set_option(asio::ip::tcp::socket::keep_alive(true));
398 // Apply the option: no delay
399 if (option_no_delay())
400 _socket.set_option(asio::ip::tcp::no_delay(true));
401
402 // Prepare receive & send buffers
403 _receive_buffer.resize(option_receive_buffer_size());
404 _send_buffer_main.reserve(option_send_buffer_size());
405 _send_buffer_flush.reserve(option_send_buffer_size());
406
407 // Reset statistic
408 _bytes_pending = 0;
409 _bytes_sending = 0;
410 _bytes_sent = 0;
411 _bytes_received = 0;
412
413 // Update the connected flag
414 _connected = true;
415
416 // Try to receive something from the server
417 TryReceive();
418
419 // Call the client connected handler
420 onConnected();
421
422 // Call the empty send buffer handler
423 if (_send_buffer_main.empty())
424 onEmpty();
425 }
426 else
427 {
428 SendError(ec2);
429
430 // Call the client disconnected handler
432 }
433 };
434 if (_strand_required)
435 asio::async_connect(_socket, endpoints, bind_executor(_strand, async_connect_handler));
436 else
437 asio::async_connect(_socket, endpoints, async_connect_handler);
438 }
439 else
440 {
441 SendError(ec1);
442
443 // Call the client disconnected handler
445 }
446 };
447
448 // Resolve the server endpoint
449 asio::ip::tcp::resolver::query query(_address, (_scheme.empty() ? std::to_string(_port) : _scheme));
450 if (_strand_required)
451 resolver->resolver().async_resolve(query, bind_executor(_strand, async_resolve_handler));
452 else
453 resolver->resolver().async_resolve(query, async_resolve_handler);
454 };
455 if (_strand_required)
456 _strand.post(connect_handler);
457 else
458 _io_service->post(connect_handler);
459
460 return true;
461}
462
463bool TCPClient::DisconnectInternalAsync(bool dispatch)
464{
465 if (!IsConnected() || _resolving || _connecting)
466 return false;
467
468 asio::error_code ec;
469
470 // Cancel the client socket
471 _socket.cancel(ec);
472
473 // Dispatch or post the disconnect handler
474 auto self(this->shared_from_this());
475 auto disconnect_handler = [this, self]() { DisconnectInternal(); };
476 if (_strand_required)
477 {
478 if (dispatch)
479 _strand.dispatch(disconnect_handler);
480 else
481 _strand.post(disconnect_handler);
482 }
483 else
484 {
485 if (dispatch)
486 _io_service->dispatch(disconnect_handler);
487 else
488 _io_service->post(disconnect_handler);
489 }
490
491 return true;
492}
493
495{
496 if (!DisconnectAsync())
497 return false;
498
499 while (IsConnected())
500 CppCommon::Thread::Yield();
501
502 return ConnectAsync();
503}
504
505size_t TCPClient::Send(const void* buffer, size_t size)
506{
507 if (!IsConnected())
508 return 0;
509
510 if (size == 0)
511 return 0;
512
513 assert((buffer != nullptr) && "Pointer to the buffer should not be null!");
514 if (buffer == nullptr)
515 return 0;
516
517 asio::error_code ec;
518
519 // Send data to the server
520 size_t sent = asio::write(_socket, asio::buffer(buffer, size), ec);
521 if (sent > 0)
522 {
523 // Update statistic
524 _bytes_sent += sent;
525
526 // Call the buffer sent handler
528 }
529
530 // Disconnect on error
531 if (ec)
532 {
533 SendError(ec);
534 Disconnect();
535 }
536
537 return sent;
538}
539
540size_t TCPClient::Send(const void* buffer, size_t size, const CppCommon::Timespan& timeout)
541{
542 if (!IsConnected())
543 return 0;
544
545 if (size == 0)
546 return 0;
547
548 assert((buffer != nullptr) && "Pointer to the buffer should not be null!");
549 if (buffer == nullptr)
550 return 0;
551
552 int done = 0;
553 std::mutex mtx;
554 std::condition_variable cv;
555 asio::error_code error;
556 asio::system_timer timer(_socket.get_executor());
557
558 // Prepare done handler
559 auto async_done_handler = [&](asio::error_code ec)
560 {
561 std::unique_lock<std::mutex> lck(mtx);
562 if (done++ == 0)
563 {
564 error = ec;
565 _socket.cancel();
566 timer.cancel();
567 }
568 cv.notify_one();
569 };
570
571 // Async wait for timeout
572 timer.expires_from_now(timeout.chrono());
573 timer.async_wait([&](const asio::error_code& ec) { async_done_handler(ec ? ec : asio::error::timed_out); });
574
575 // Async write some data to the server
576 size_t sent = 0;
577 _socket.async_write_some(asio::buffer(buffer, size), [&](std::error_code ec, size_t write) { async_done_handler(ec); sent = write; });
578
579 // Wait for complete or timeout
580 std::unique_lock<std::mutex> lck(mtx);
581 cv.wait(lck, [&]() { return done == 2; });
582
583 // Send data to the server
584 if (sent > 0)
585 {
586 // Update statistic
587 _bytes_sent += sent;
588
589 // Call the buffer sent handler
591 }
592
593 // Disconnect on error
594 if (error && (error != asio::error::timed_out))
595 {
596 SendError(error);
597 Disconnect();
598 }
599
600 return sent;
601}
602
603bool TCPClient::SendAsync(const void* buffer, size_t size)
604{
605 if (!IsConnected())
606 return false;
607
608 if (size == 0)
609 return true;
610
611 assert((buffer != nullptr) && "Pointer to the buffer should not be null!");
612 if (buffer == nullptr)
613 return false;
614
615 {
616 std::scoped_lock locker(_send_lock);
617
618 // Detect multiple send handlers
619 bool send_required = _send_buffer_main.empty() || _send_buffer_flush.empty();
620
621 // Check the send buffer limit
622 if (((_send_buffer_main.size() + size) > _send_buffer_limit) && (_send_buffer_limit > 0))
623 {
624 SendError(asio::error::no_buffer_space);
625 return false;
626 }
627
628 // Fill the main send buffer
629 const uint8_t* bytes = (const uint8_t*)buffer;
630 _send_buffer_main.insert(_send_buffer_main.end(), bytes, bytes + size);
631
632 // Update statistic
633 _bytes_pending = _send_buffer_main.size();
634
635 // Avoid multiple send handlers
636 if (!send_required)
637 return true;
638 }
639
640 // Dispatch the send handler
641 auto self(this->shared_from_this());
642 auto send_handler = [this, self]()
643 {
644 // Try to send the main buffer
645 TrySend();
646 };
647 if (_strand_required)
648 _strand.dispatch(send_handler);
649 else
650 _io_service->dispatch(send_handler);
651
652 return true;
653}
654
655size_t TCPClient::Receive(void* buffer, size_t size)
656{
657 if (!IsConnected())
658 return 0;
659
660 if (size == 0)
661 return 0;
662
663 assert((buffer != nullptr) && "Pointer to the buffer should not be null!");
664 if (buffer == nullptr)
665 return 0;
666
667 asio::error_code ec;
668
669 // Receive data from the server
670 size_t received = _socket.read_some(asio::buffer(buffer, size), ec);
671 if (received > 0)
672 {
673 // Update statistic
674 _bytes_received += received;
675
676 // Call the buffer received handler
678 }
679
680 // Disconnect on error
681 if (ec)
682 {
683 SendError(ec);
684 Disconnect();
685 }
686
687 return received;
688}
689
690std::string TCPClient::Receive(size_t size)
691{
692 std::string text(size, 0);
693 text.resize(Receive(text.data(), text.size()));
694 return text;
695}
696
697size_t TCPClient::Receive(void* buffer, size_t size, const CppCommon::Timespan& timeout)
698{
699 if (!IsConnected())
700 return 0;
701
702 if (size == 0)
703 return 0;
704
705 assert((buffer != nullptr) && "Pointer to the buffer should not be null!");
706 if (buffer == nullptr)
707 return 0;
708
709 int done = 0;
710 std::mutex mtx;
711 std::condition_variable cv;
712 asio::error_code error;
713 asio::system_timer timer(_socket.get_executor());
714
715 // Prepare done handler
716 auto async_done_handler = [&](asio::error_code ec)
717 {
718 std::unique_lock<std::mutex> lck(mtx);
719 if (done++ == 0)
720 {
721 error = ec;
722 _socket.cancel();
723 timer.cancel();
724 }
725 cv.notify_one();
726 };
727
728 // Async wait for timeout
729 timer.expires_from_now(timeout.chrono());
730 timer.async_wait([&](const asio::error_code& ec) { async_done_handler(ec ? ec : asio::error::timed_out); });
731
732 // Async read some data from the server
733 size_t received = 0;
734 _socket.async_read_some(asio::buffer(buffer, size), [&](std::error_code ec, size_t read) { async_done_handler(ec); received = read; });
735
736 // Wait for complete or timeout
737 std::unique_lock<std::mutex> lck(mtx);
738 cv.wait(lck, [&]() { return done == 2; });
739
740 // Received some data from the server
741 if (received > 0)
742 {
743 // Update statistic
744 _bytes_received += received;
745
746 // Call the buffer received handler
748 }
749
750 // Disconnect on error
751 if (error && (error != asio::error::timed_out))
752 {
753 SendError(error);
754 Disconnect();
755 }
756
757 return received;
758}
759
760std::string TCPClient::Receive(size_t size, const CppCommon::Timespan& timeout)
761{
762 std::string text(size, 0);
763 text.resize(Receive(text.data(), text.size(), timeout));
764 return text;
765}
766
768{
769 // Try to receive data from the server
770 TryReceive();
771}
772
773void TCPClient::TryReceive()
774{
775 if (_receiving)
776 return;
777
778 if (!IsConnected())
779 return;
780
781 // Async receive with the receive handler
782 _receiving = true;
783 auto self(this->shared_from_this());
784 auto async_receive_handler = make_alloc_handler(_receive_storage, [this, self](std::error_code ec, size_t size)
785 {
786 _receiving = false;
787
788 if (!IsConnected())
789 return;
790
791 // Received some data from the server
792 if (size > 0)
793 {
794 // Update statistic
795 _bytes_received += size;
796
797 // Call the buffer received handler
798 onReceived(_receive_buffer.data(), size);
799
800 // If the receive buffer is full increase its size
801 if (_receive_buffer.size() == size)
802 {
803 // Check the receive buffer limit
804 if (((2 * size) > _receive_buffer_limit) && (_receive_buffer_limit > 0))
805 {
806 SendError(asio::error::no_buffer_space);
807 DisconnectInternalAsync(true);
808 return;
809 }
810
811 _receive_buffer.resize(2 * size);
812 }
813 }
814
815 // Try to receive again if the session is valid
816 if (!ec)
817 TryReceive();
818 else
819 {
820 SendError(ec);
821 DisconnectInternalAsync(true);
822 }
823 });
824 if (_strand_required)
825 _socket.async_read_some(asio::buffer(_receive_buffer.data(), _receive_buffer.size()), bind_executor(_strand, async_receive_handler));
826 else
827 _socket.async_read_some(asio::buffer(_receive_buffer.data(), _receive_buffer.size()), async_receive_handler);
828}
829
830void TCPClient::TrySend()
831{
832 if (_sending)
833 return;
834
835 if (!IsConnected())
836 return;
837
838 // Swap send buffers
839 if (_send_buffer_flush.empty())
840 {
841 std::scoped_lock locker(_send_lock);
842
843 // Swap flush and main buffers
844 _send_buffer_flush.swap(_send_buffer_main);
845 _send_buffer_flush_offset = 0;
846
847 // Update statistic
848 _bytes_pending = 0;
849 _bytes_sending += _send_buffer_flush.size();
850 }
851
852 // Check if the flush buffer is empty
853 if (_send_buffer_flush.empty())
854 {
855 // Call the empty send buffer handler
856 onEmpty();
857 return;
858 }
859
860 // Async write with the write handler
861 _sending = true;
862 auto self(this->shared_from_this());
863 auto async_write_handler = make_alloc_handler(_send_storage, [this, self](std::error_code ec, size_t size)
864 {
865 _sending = false;
866
867 if (!IsConnected())
868 return;
869
870 // Send some data to the server
871 if (size > 0)
872 {
873 // Update statistic
874 _bytes_sending -= size;
875 _bytes_sent += size;
876
877 // Increase the flush buffer offset
878 _send_buffer_flush_offset += size;
879
880 // Successfully send the whole flush buffer
881 if (_send_buffer_flush_offset == _send_buffer_flush.size())
882 {
883 // Clear the flush buffer
884 _send_buffer_flush.clear();
885 _send_buffer_flush_offset = 0;
886 }
887
888 // Call the buffer sent handler
889 onSent(size, bytes_pending());
890 }
891
892 // Try to send again if the session is valid
893 if (!ec)
894 TrySend();
895 else
896 {
897 SendError(ec);
898 DisconnectInternalAsync(true);
899 }
900 });
901 if (_strand_required)
902 _socket.async_write_some(asio::buffer(_send_buffer_flush.data() + _send_buffer_flush_offset, _send_buffer_flush.size() - _send_buffer_flush_offset), bind_executor(_strand, async_write_handler));
903 else
904 _socket.async_write_some(asio::buffer(_send_buffer_flush.data() + _send_buffer_flush_offset, _send_buffer_flush.size() - _send_buffer_flush_offset), async_write_handler);
905}
906
907void TCPClient::ClearBuffers()
908{
909 {
910 std::scoped_lock locker(_send_lock);
911
912 // Clear send buffers
913 _send_buffer_main.clear();
914 _send_buffer_flush.clear();
915 _send_buffer_flush_offset = 0;
916
917 // Update statistic
918 _bytes_pending = 0;
919 _bytes_sending = 0;
920 }
921}
922
923void TCPClient::SendError(std::error_code ec)
924{
925 // Skip Asio disconnect errors
926 if ((ec == asio::error::connection_aborted) ||
927 (ec == asio::error::connection_refused) ||
928 (ec == asio::error::connection_reset) ||
929 (ec == asio::error::eof) ||
930 (ec == asio::error::operation_aborted))
931 return;
932
933 onError(ec.value(), ec.category().name(), ec.message());
934}
935
936} // namespace Asio
937} // namespace CppServer
Asio allocate handler wrapper.
Definition memory.h:133
size_t option_send_buffer_size() const
Get the option: send buffer size.
virtual size_t Receive(void *buffer, size_t size)
Receive data from the server (synchronous)
bool IsConnected() const noexcept
Is the client connected?
Definition tcp_client.h:101
virtual bool Connect()
Connect the client (synchronous)
virtual size_t Send(const void *buffer, size_t size)
Send data to the server (synchronous)
TCPClient(const std::shared_ptr< Service > &service, const std::string &address, int port)
Initialize TCP client with a given Asio service, server address and port number.
virtual bool Disconnect()
Disconnect the client (synchronous)
Definition tcp_client.h:124
virtual bool SendAsync(const void *buffer, size_t size)
Send data to the server (asynchronous)
virtual void onSent(size_t sent, size_t pending)
Handle buffer sent notification.
Definition tcp_client.h:303
virtual bool ReconnectAsync()
Reconnect the client (asynchronous)
virtual void onReceived(const void *buffer, size_t size)
Handle buffer received notification.
Definition tcp_client.h:291
virtual void onDisconnected()
Handle client disconnected notification.
Definition tcp_client.h:281
virtual void onConnected()
Handle client connected notification.
Definition tcp_client.h:279
void SetupReceiveBufferSize(size_t size)
Setup option: receive buffer size.
virtual void onEmpty()
Handle empty send buffer notification.
Definition tcp_client.h:312
virtual void onError(int error, const std::string &category, const std::string &message)
Handle error notification.
Definition tcp_client.h:320
std::shared_ptr< Service > & service() noexcept
Get the Asio service.
Definition tcp_client.h:63
uint64_t bytes_pending() const noexcept
Get the number of bytes pending sent by the client.
Definition tcp_client.h:81
virtual bool ConnectAsync()
Connect the client (asynchronous)
bool option_no_delay() const noexcept
Get the option: no delay.
Definition tcp_client.h:90
asio::ip::tcp::endpoint & endpoint() noexcept
Get the client endpoint.
Definition tcp_client.h:69
virtual bool DisconnectAsync()
Disconnect the client (asynchronous)
Definition tcp_client.h:146
bool option_keep_alive() const noexcept
Get the option: keep alive.
Definition tcp_client.h:88
virtual void ReceiveAsync()
Receive data from the server (asynchronous)
void SetupSendBufferSize(size_t size)
Setup option: send buffer size.
size_t option_receive_buffer_size() const
Get the option: receive buffer size.
virtual bool Reconnect()
Reconnect the client (synchronous)
AllocateHandler< THandler > make_alloc_handler(HandlerStorage &storage, THandler handler)
Helper function to wrap a handler object to add custom allocation.
Definition memory.inl:39
C++ Server project definitions.
Definition asio.h:56
TCP client definition.