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