Слияние кода завершено, страница обновится автоматически
Заголовок только C++ сетевая библиотека, основанная на asio, поддерживает TCP, UDP, HTTP, WebSocket, RPC, SSL, ICMP, Serial Port.
В настоящее время многие фреймворки, основанные на asio, имеют следующий режим работы:
tcp_server server; // Объявить сервер
server.run(); // Вызов функции run, функция run блокирующая, после вызова run непонятно, как выйти.
Этот режим требует, чтобы пользователь сам обрабатывал логику выхода программы после завершения соединения, включая нормальное закрытие соединения, освобождение ресурсов и другие проблемы, которые сложно решить самостоятельно.
Фреймворк asio2 уже решил эти проблемы. Вы можете вызвать server.start(...) в таких местах, как MFC OnInitDialog, start(...) — это неблокирующая функция, когда вы хотите выйти, просто вызовите server.stop(). stop() — блокирующая функция.
При остановке, если есть данные, которые не были отправлены, она обязательно будет отправлена перед выходом.
TCP также гарантирует, что все соединения будут нормально закрыты после выхода, вам не нужно беспокоиться о правильной очистке ресурсов и других мелких проблемах.
asio2::tcp_server server;
server.bind_recv([&](std::shared_ptr<asio2::tcp_session> & session_ptr, std::string_view s)
{
printf("recv : %zu %.*s\n", s.size(), (int)s.size(), s.data());
// Асинхронная отправка (все операции отправки являются асинхронными и потокобезопасными)
session_ptr->async_send(s);
// При отправке укажите функцию обратного вызова. После завершения отправки эта функция обратного вызова будет вызвана. bytes_sent представляет количество фактически отправленных байтов.
// Можно использовать asio2::get_last_error() для получения кода ошибки при возникновении ошибки отправки
// session_ptr->async_send(s, [](std::size_t bytes_sent) {});
}).bind_connect([&](auto & session_ptr)
{
session_ptr->no_delay(true);
printf("client enter : %s %u %s %u\n",
session_ptr->remote_address().c_str(), session_ptr->remote_port(),
session_ptr->local_address().c_str(), session_ptr->local_port());
// Здесь можно использовать session_ptr для запуска таймера в сеансе. Этот таймер выполняется в потоке обработки данных сеанса. Это полезно для определения состояния соединения или других требований (особенно в протоколах без установления соединения, таких как UDP, иногда требуется использовать таймер в процессе обработки данных для задержки некоторых операций, и этот таймер должен быть безопасным для совместного использования данных)
//session_ptr->start_timer(1, std::chrono::seconds(1), []() {});
}).bind_disconnect([&](auto & session_ptr)
{
printf("client leave : %s %u %s\n",
session_ptr->remote_address().c_str(), session_ptr->remote_port(),
asio2::last_error_msg().c_str());
});
server.start("0.0.0.0", "8080");
// Автоматическое разделение пакетов по \n (можно указать любой символ)
//server.start("0.0.0.0", "8080", '\n');
// Автоматическое разделение пакетов по \r\n (можно указать любую строку)
//server.start("0.0.0.0", "8080", "\r\n");
// Разделение пакетов по пользовательскому правилу (match_role см. пример кода) (используется для разделения пользовательских протоколов)
// Для разделения пользовательского протокола, пожалуйста, обратитесь к подробному объяснению использования match_role (#): https://blog.csdn.net/zhllxt/article/details/104772948
//server.start("0.0.0.0", "8080", match_role('#'));
// Каждый раз получать фиксированные 100 байт данных
//server.start("0.0.0.0", "8080", asio::transfer_exactly(100));
// Режим данных дейтаграмм TCP. Независимо от того, сколько данных отправлено, получатель всегда получает полный пакет данных
//server.start("0.0.0.0", "8080", asio2::use_dgram);
asio2::tcp_client client;
// Клиент автоматически переподключится после разрыва соединения
// Запретить автоматическое переподключение
//client.auto_reconnect(false);
// Включить автоматическое переподключение. По умолчанию клиент будет пытаться повторно подключиться через 1 секунду после разрыва соединения.
//client.auto_reconnect(true);
// Включите автоматическое переподключение и установите собственное время ожидания
client.auto_reconnect(true, std::chrono::seconds(3));
client.bind_connect([&]()
{
if (asio2::get_last_error())
printf("connect failure : %d %s\n", asio2::last_error_val(), asio2::last_error_msg().c_str());
else
printf("connect success : %s %u\n", client.local_address().c_str(), client.local_port());
// Если соединение успешно установлено, можно вызвать функцию async_send для отправки данных.
if (!asio2::get_last_error())
client.async_send("<abcdefghijklmnopqrstovuxyz0123456789>");
// Если вызов функции send в коммуникационном потоке приведёт к асинхронному вызову (здесь обратный вызов bind_connect находится в коммуникационном потоке)
// client.send("abc");
}).bind_disconnect([]()
{
printf("disconnect : %d %s\n",
``` Данный фрагмент написан на языке C++.
В тексте описывается использование библиотеки asio2 для разработки сетевых приложений. В частности, рассматриваются примеры использования различных функций и классов этой библиотеки для создания TCP-соединений, отправки и получения данных, а также для реализации RPC (удаленного вызова процедур).
Текст содержит фрагменты кода, которые демонстрируют использование различных методов и функций библиотеки asio2.
**Перевод фрагмента:**
```cpp
// 异步连接服务端
client.async_start("0.0.0.0", "8080");
// 同步连接服务端
client.start("0.0.0.0", "8080");
// Соединение успешно установлено, можно вызвать функцию отправки (здесь основной поток не находится в потоке связи)
// Синхронная отправка и асинхронная отправка могут использоваться совместно, это потокобезопасно (обязательно будет выполнена после завершения отправки A, затем будет выполнена отправка B)
std::size_t bytes_sent = client.send("abc");
// Функция синхронной отправки возвращает количество отправленных байтов. Можно использовать get_last_error() для проверки наличия ошибки
if (asio2::get_last_error()) {
printf("Синхронная отправка данных не удалась:%s\n", asio2::last_error_msg().data());
}
// Автоматическая разборка пакетов по \n (можно указать любой символ)
//client.async_start("0.0.0.0", "8080", '\n');
// Автоматическая разборка пакетов по \r\n (можно указать любую строку)
//client.async_start("0.0.0.0", "8080", "\r\n");
// Автоматическая разборка пакетов с использованием пользовательских правил (match_role см. пример кода) (используется для разбора пользовательского протокола)
// Для пользовательской разборки пакетов match_role используется следующим образом: см. https://blog.csdn.net/zhllxt/article/details/104772948
//client.async_start("0.0.0.0", "8080", match_role);
// Каждый раз получать фиксированные 100 байт
//client.async_start("0.0.0.0", "8080", asio::transfer_exactly(100));
// Режим данных пакета TCP, независимо от длины отправляемых данных, получатель всегда получает пакет данных соответствующей длины
//client.start("0.0.0.0", "8080", asio2::use_dgram);
// При отправке также можно указать параметр use_future, а затем использовать возвращаемое значение future для блокировки ожидания завершения отправки. Ошибки и количество отправленных байт сохраняются в возвращаемом значении future (обратите внимание, что нельзя использовать future в потоке связи, это заблокирует поток связи и приведёт к тупиковой ситуации)
// std::future<std::pair<asio::error_code, std::size_t>> future = client.async_send("abc", asio::use_future);
Сервер:
asio2::udp_server server;
// ... Привязка слушателя (см. пример кода)
server.start("0.0.0.0", "8080"); // Обычный UDP
//server.start("0.0.0.0", "8080", asio2::use_kcp); // Надежный UDP
Клиент:
asio2::udp_client client;
// ... Привязать слушателя (см. пример кода)
client.start("0.0.0.0", "8080");
//client.async_start("0.0.0.0", "8080", asio2::use_kcp); // Надежный UDP
Сервер:
// Пример глобальной функции: когда функция RPC сервера вызывается, если вы хотите знать, какой клиент вызвал её, установите первый
// параметр этой функции RPC как указатель на интеллектуальный указатель соединения (если вам не важно, какой клиент вызывает его, первый параметр можно опустить), например:
int add(std::shared_ptr<asio2::rpc_session>& session_ptr, int a, int b) {
return a + b;
}
// По умолчанию RPC использует формат «длина данных + данные» для отправки данных. Поэтому клиент может злонамеренно создавать пакеты, что приводит к анализу «длины данных», которая становится очень длинной. В этом случае будет выделено большое количество памяти для приёма полного пакета данных. Чтобы избежать этой проблемы, можно указать максимальный размер буфера приёма. Если отправленные данные превышают максимальный размер буфера, соединение будет немедленно закрыто. Все tcp udp http websocket, сервер и клиент поддерживают эту функцию.
asio2::rpc_server server(
512, // Начальный размер приёмного буфера
1024, // Максимальный размер приёмного буфера
4 // Количество параллельных потоков
);
// ... Привязать слушателя (см. пример кода)
// Связать глобальную функцию RPC
server.bind("add", add);
// Связать функцию-член RPC
server.bind("mul", &A::mul, a);
// Связать лямбда-выражение
server.bind("cat", [&](const std::string& a, const std::string& b) { return a + b; });
// Связать функцию-член (по ссылке) определение a см. в примере кода
server.bind("get_user", &A::get_user, a);
// Связать функцию-член (по указателю) определение a см. в примере кода
server.bind("del_user", &A::del_user, &a);
// Сервер также может вызывать функции RPC клиента (через объект соединения session_ptr)
session_ptr->async_call([](int v) {
printf("sub : %d err : %d %s\n", v, asio2::last_error_val(), asio2::last_error_msg().c_str());
}, std::chrono::seconds(10), "sub", 15, 6);
server.start("0.0.0.0", "8080");
Клиент:
asio2::rpc_client client;
// ... Привязать слушателя (см. пример кода)
// Не только сервер может привязывать функции RPC для вызова клиентом, но и клиент также может привязывать функции RPC для вызова сервера. См. пример кода.
client.start("0.0.0.0", "8080");
// Вызов функции RPC синхронно
int sum = client.call<int>(std::chrono::seconds(3), "add", 11, 2);
printf("sum : %d err : %d %s\n", sum, asio2::last_error_val(), asio2::last_error_msg().c_str());
// Асинхронный вызов функции RPC. Первый параметр — это функция обратного вызова, которая автоматически вызывается при завершении вызова или истечении времени ожидания. Второй параметр — время ожидания вызова, которое можно не указывать. Третий параметр — имя функции RPC, а последующие параметры — аргументы функции RPC.
client.async_call([](int v) {
// Если время ожидания истекло или произошла другая ошибка, можно получить информацию об ошибке через asio2::get_last_error() и другие функции.
printf("sum : %d err : %d %s\n", v, asio2::last_error_val(), asio2::last_error_msg().c_str());
}, "add", 10, 20);
// Вышеупомянутый способ вызова параметров легко спутать, поэтому поддерживается цепочка вызовов, например (другие примеры см. в коде):
client.timeout(std::chrono::seconds(5)).async_call("mul", 2.5, 2.5).response(
[](double v) {
std::cout << "mul1 " << v << std::endl;
});
int sum = client.timeout(std::chrono::seconds(3)).call<int>("add", 11, 32);
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )