1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/zhllxt-asio2

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
README.md 19 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 28.11.2024 10:53 f491b61

Заголовок только C++ сетевая библиотека, основанная на asio, поддерживает TCP, UDP, HTTP, WebSocket, RPC, SSL, ICMP, Serial Port.

996.icu 996.icu LICENSE

  • Заголовок только, не зависит от библиотеки Boost, не требует отдельной компиляции, в каталоге Include проекта добавьте путь к asio2, в исходном коде #include <asio2/asio2.hpp>, чтобы использовать;
  • Поддерживает TCP, UDP, HTTP, WebSocket, RPC, SSL, ICMP, Serial Port;
  • Поддержка надёжного UDP (на основе KCP), поддержка SSL;
  • TCP поддерживает различные функции разделения данных (отдельные символы или строки или пользовательские протоколы и т. д.);
  • Кроссплатформенность, поддержка Windows, Linux, macOS, ARM, Android, 32-битные и 64-битные системы и т.д.; компилируется под msvc, gcc, clang, ndk, mingw;
  • Основан на C++17, основан на asio (standalone asio или boost::asio оба могут использоваться);
  • В каталоге example содержится множество примеров кода, для ознакомления с различными методами использования см. примеры кода;

QQ группа общения: 833425075

Некоторые базовые статьи по использованию:

Отличия от других фреймворков:

В настоящее время многие фреймворки, основанные на asio, имеют следующий режим работы:
tcp_server server; // Объявить сервер
server.run();      // Вызов функции run, функция run блокирующая, после вызова run непонятно, как выйти.
Этот режим требует, чтобы пользователь сам обрабатывал логику выхода программы после завершения соединения, включая нормальное закрытие соединения, освобождение ресурсов и другие проблемы, которые сложно решить самостоятельно.
Фреймворк asio2 уже решил эти проблемы. Вы можете вызвать server.start(...) в таких местах, как MFC OnInitDialog, start(...)  это неблокирующая функция, когда вы хотите выйти, просто вызовите server.stop(). stop()  блокирующая функция.
При остановке, если есть данные, которые не были отправлены, она обязательно будет отправлена перед выходом.
TCP также гарантирует, что все соединения будут нормально закрыты после выхода, вам не нужно беспокоиться о правильной очистке ресурсов и других мелких проблемах.

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);
  • UDP:

Сервер:

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 сервера вызывается, если вы хотите знать, какой клиент вызвал её, установите первый
// параметр этой функции 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 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/zhllxt-asio2.git
git@api.gitlife.ru:oschina-mirror/zhllxt-asio2.git
oschina-mirror
zhllxt-asio2
zhllxt-asio2
main