Вступление
Создание Telegram-ботов обычно ассоциируется с Python , но C++ — это мощная альтернатива для тех, кто ценит производительность и контроль над ресурсами. Использовать мы будем библиотеку Boost для работы с https запросами.

Если нужен только проект то он есть на гитхабе https://github.com/sergey00010/telegram_bot_cpp_boost
CMakeList.txt
Я в проекте буду использовать систему сборки cmake, т.к она очень удобна по многим причинам.
для начала укажем версию cmake, название проекта, и стандарт плюсов
cmake_minimum_required(VERSION 3.14) project(TelegramBot) set(CMAKE_CXX_STANDARD 17)
Далее укажем какие библиотеки мы будем использовать, Boost для работы с сетью, nlohmann_json для парсинга json и OpenSSL чтобы мы могли работать не только с http, но и с https запросами
find_package(Boost REQUIRED COMPONENTS system) find_package(nlohmann_json REQUIRED) find_package(OpenSSL REQUIRED) target_link_libraries(tgBot Boost::system OpenSSL::SSL OpenSSL::Crypto nlohmann_json::nlohmann_json )
Далее мы добавим все наши файлы в проект, все функции для бота будем создавать в отдельном классе, поэтому создаем файлы TelegramBot.cpp и TelegramBot.h
add_executable(tgBot src/main.cpp src/TelegramBot.cpp src/TelegramBot.h )
теперь cmake выглядит так:
cmake_minimum_required(VERSION 3.14) project(TelegramBot) set(CMAKE_CXX_STANDARD 17) find_package(Boost REQUIRED COMPONENTS system) find_package(nlohmann_json REQUIRED) find_package(OpenSSL REQUIRED) add_executable(tgBot src/main.cpp src/TelegramBot.cpp src/TelegramBot.h ) target_link_libraries(tgBot Boost::system OpenSSL::SSL OpenSSL::Crypto nlohmann_json::nlohmann_json )
TelegramBot.h
Для начала добавим библиотеки, которые будем использовать, далее в классе создаем конструктор в который будем передавать токен бота и функцию, которая нужна для ответа пользователю. Далее добавляем функцию для запуска бота.
//transfer telegram bot token and function which use after get new message TelegramBot(const std::string& token, const std::function<std::string()> &funcAnswer); //start bot void start();
После добавляем переменные,
apiUrl - в нее будем писать адрес телеграм апи + токен
botToken - в нее будем писать токен бота
lastUpdateId - используется для отслеживания последнего обработанного обновления от Telegram API, для того, чтобы бот не обрабатывал одни и те же обновления повторно.
std::string apiUrl; std::string botToken; std::string lastUpdateId;
Далее добавляем функции
void handleUpdates(const nlohmann::json& updates) - Обработка полученных обновлений. updates: JSON-объект, содержащий список обновлений.
void sendMessage(const std::string& chatId, const std::string& text) - Отправка сообщения в указанный чат. chatid Идентификатор чата, куда нужно отправить сообщение. text: Текст сообщения.
nlohmann::json makeRequest(const std::string& method, const nlohmann::json& payload = {}) - Выполнение HTTP-запросов к Telegram API. method: Метод Telegram API (например, getUpdates или sendMessage). payload: JSON-объект с параметрами запроса.
//process new messages void handleUpdates(const nlohmann::json& updates); //create new json and transfer to make request void sendMessage(const std::string& chatId, const std::string& text); //make request to api telegram server nlohmann::json makeRequest(const std::string& method, const nlohmann::json& payload = {});
В переменную std::function funcAnswer будет писаться функция из конструктора класса, и уже ее мы будем вызывать, чтобы ответить пользователю.
Весь код:
#ifndef TELEGRAMBOT_H #define TELEGRAMBOT_H #include <string> #include <boost/beast.hpp> #include <nlohmann/json.hpp> #include <functional> class TelegramBot { public: //transfer telegram bot token and function which use after get new message TelegramBot(const std::string& token, const std::function<std::string()> &funcAnswer); //start bot void start(); private: std::string apiUrl; std::string botToken; std::string lastUpdateId; //process new messages void handleUpdates(const nlohmann::json& updates); //create new json and transfer to make request void sendMessage(const std::string& chatId, const std::string& text); //make request to api telegram server nlohmann::json makeRequest(const std::string& method, const nlohmann::json& payload = {}); std::function<std::string()> funcAnswer; }; #endif // TELEGRAMBOT_H
TelegramBot.cpp
для начала добавляем все необходимые библеотеки, после создаем псевдоним tcp для типа и псевдоним для пространства имен для более удобной работы.
#include "TelegramBot.h" #include <iostream> #include <boost/asio.hpp> #include <boost/asio/ssl.hpp> #include <boost/beast.hpp> #include <boost/beast/ssl.hpp> using tcp = boost::asio::ip::tcp; namespace http = boost::beast::http;
После создаем конструктор, который настраивает бота, сохраняя токен и функцию для генерации ответов.
TelegramBot::TelegramBot(const std::string& token, const std::function<std::string()> &funcAnswer) : botToken(token), apiUrl("https://api.telegram.org/bot" + token) , funcAnswer(funcAnswer) {}
Далее создаем функцию start
это основной цикл работы Telegram-бота. Она отвечает за:
Запрос обновлений от Telegram API (новых сообщений, событий)
Обработку обновлений (например, ответ на сообщения пользователя)
Бесконечный цикл, чтобы бот работал постоянно
void TelegramBot::start() { while (true) { try { /* * Создается JSON-объект payload, * который будет отправлен в запросе к Telegram API. * * Если lastUpdateId не пуст * (то есть бот уже обработал какие-то обновления ранее), * в payload добавляется параметр offset. * Это нужно, чтобы бот получал только новые обновления, * начиная с последнего обработанного update_id + 1. */ nlohmann::json payload; if (!lastUpdateId.empty()) { payload["offset"] = std::stoi(lastUpdateId) + 1; } /* Вызывается функция makeRequest, * которая отправляет HTTP-запрос к Telegram API * с методом getUpdates. * В ответ приходит JSON-объект response, * содержащий список обновлений */ В ответ приходит JSON-объект response, содержащий список обновлений (новые сообщения, события и т.д.). auto response = makeRequest("getUpdates", payload); /* Обработка полученных обновлений * Функция handleUpdates принимает массив обновлений * (response["result"]) * и обрабатывает каждое из них. * Например, если пришло новое сообщение, бот может отправить ответ. */ handleUpdates(response["result"]); } catch (const std::exception& e) { // Обработка ошибок std::cerr << "Error: " << e.what() << std::endl; } } }
Далее добавляем функцию handleUpdates
Функция отвечает за обработку обновлений, полученных от Telegram API. Она анализирует каждое обновление, извлекает полезную информацию (текст сообщения и ID чата) и отправляет ответ пользователю
void TelegramBot::handleUpdates(const nlohmann::json& updates) { for (const auto& update : updates) { // Сохраняем ID последнего обновления if (update.contains("update_id")) { lastUpdateId = std::to_string(update["update_id"].get<int>()); } // Проверяем, содержит ли обновление сообщение с текстом if (update.contains("message") && update["message"].contains("text")) { // Извлекаем ID чата и текст сообщения std::string chatId = std::to_string(update["message"]["chat"]["id"].get<int>()); // тут нигде я не буду применять эту переменную, // но добавил ее для информативности std::string text = update["message"]["text"].get<std::string>(); // Формируем ответное сообщение (бот будет присылать температуру gpu) std::string respText = "Gpu temp: " + funcAnswer(); // Отправляем ответ пользователю sendMessage(chatId, respText); } } }
Далее создаем функцию sendMessage
Функция отвечает за отправку сообщения в указанный чат через Telegram API.
void TelegramBot::sendMessage(const std::string& chatId, const std::string& text) { // Создаем JSON-объект с данными для отправки nlohmann::json payload; payload["chat_id"] = chatId; payload["text"] = text; // Вызываем makeRequest для отправки сообщения через API Telegram makeRequest("sendMessage", payload); }
Далее создаем функцию makeRequest
Функция выполняет HTTP-запрос к Telegram API с использованием библиотек Boost.Asio и Boost.Beast. Она отправляет данные (сообщение) и получает ответ от сервера.
nlohmann::json TelegramBot::makeRequest(const std::string& method, const nlohmann::json& payload) { try { // Создаем контекст ввода-вывода boost::asio::io_context ioc; // Настраиваем SSL-контекст boost::asio::ssl::context ssl_ctx(boost::asio::ssl::context::tlsv12_client); //загружает стандартные сертификаты для проверки подлинности сервера. ssl_ctx.set_default_verify_paths(); // Создаем резолвер и SSL-поток // преобразует доменное имя в IP-адрес. tcp::resolver resolver(ioc); // это SSL-поток, который поверх обычного TCP-потока добавляет шифрование. boost::beast::ssl_stream<boost::beast::tcp_stream> stream(ioc, ssl_ctx); // Разрешаем доменное имя и устанавливаем соединение auto const results = resolver.resolve("api.telegram.org", "443"); boost::beast::get_lowest_layer(stream).connect(results); // Выполняется SSL-рукопожатие для установки защищенного соединения. stream.handshake(boost::asio::ssl::stream_base::client); // Создаем HTTP-запрос http::request<http::string_body> req{http::verb::post, "/bot" + botToken + "/" + method, 11}; req.set(http::field::host, "api.telegram.org"); req.set(http::field::content_type, "application/json"); req.body() = payload.dump(); req.prepare_payload(); // Отправляем запрос http::write(stream, req); // Получаем ответ boost::beast::flat_buffer buffer; http::response<http::string_body> res; http::read(stream, buffer, res); // Закрываем SSL-соединение boost::system::error_code ec; stream.shutdown(ec); // 1Игнорируем ошибку "stream truncated" // (она часто возникает при закрытии SSL) if (ec == boost::asio::ssl::error::stream_truncated) { ec.assign(0, ec.category()); } else if (ec) { throw boost::system::system_error(ec); } // Парсим и возвращаем ответ в формате JSON return nlohmann::json::parse(res.body()); } catch (const std::exception& e) { // Обрабатываем ошибки throw std::runtime_error(std::string("Request failed: ") + e.what()); } }
Весь код:
#include "TelegramBot.h" #include <iostream> #include <boost/asio.hpp> #include <boost/asio/ssl.hpp> #include <boost/beast.hpp> #include <boost/beast/ssl.hpp> using tcp = boost::asio::ip::tcp; namespace http = boost::beast::http; TelegramBot::TelegramBot(const std::string& token, const std::function<std::string()> &funcAnswer) : botToken(token), apiUrl("https://api.telegram.org/bot" + token) , funcAnswer(funcAnswer) {} void TelegramBot::start() { while (true) { try { // Get updates nlohmann::json payload; if (!lastUpdateId.empty()) { payload["offset"] = std::stoi(lastUpdateId) + 1; } auto response = makeRequest("getUpdates", payload); handleUpdates(response["result"]); } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; } } } void TelegramBot::handleUpdates(const nlohmann::json& updates) { for (const auto& update : updates) { if (update.contains("update_id")) { lastUpdateId = std::to_string(update["update_id"].get<int>()); } if (update.contains("message") && update["message"].contains("text")) { std::string chatId = std::to_string(update["message"]["chat"]["id"].get<int>()); std::string text = update["message"]["text"].get<std::string>(); std::string respText = "Gpu temp: " + funcAnswer(); sendMessage(chatId, respText); } } } void TelegramBot::sendMessage(const std::string& chatId, const std::string& text) { nlohmann::json payload; payload["chat_id"] = chatId; payload["text"] = text; makeRequest("sendMessage", payload); } nlohmann::json TelegramBot::makeRequest(const std::string& method, const nlohmann::json& payload) { try { boost::asio::io_context ioc; // SSL Context boost::asio::ssl::context ssl_ctx(boost::asio::ssl::context::tlsv12_client); ssl_ctx.set_default_verify_paths(); tcp::resolver resolver(ioc); boost::beast::ssl_stream<boost::beast::tcp_stream> stream(ioc, ssl_ctx); // Resolve host and connect auto const results = resolver.resolve("api.telegram.org", "443"); boost::beast::get_lowest_layer(stream).connect(results); // Perform SSL handshake stream.handshake(boost::asio::ssl::stream_base::client); // Create HTTP request http::request<http::string_body> req{http::verb::post, "/bot" + botToken + "/" + method, 11}; req.set(http::field::host, "api.telegram.org"); req.set(http::field::content_type, "application/json"); req.body() = payload.dump(); req.prepare_payload(); // Send the request http::write(stream, req); // Receive the response boost::beast::flat_buffer buffer; http::response<http::string_body> res; http::read(stream, buffer, res); // Shut down the SSL stream boost::system::error_code ec; stream.shutdown(ec); // Ignore the "stream truncated" error, as it is common during SSL shutdown if (ec == boost::asio::ssl::error::stream_truncated) { ec.assign(0, ec.category()); } else if (ec) { throw boost::system::system_error(ec); } // Parse and return the response body as JSON return nlohmann::json::parse(res.body()); } catch (const std::exception& e) { throw std::runtime_error(std::string("Request failed: ") + e.what()); } }
main.cpp
Теперь функция main, тут просто будем запускать бота, в конструктор можно любую функцию передавать, которая будет возвращать string, это и будет ответным сообщением бота, я передаю температуру gpu через лямбду функции
#include "TelegramBot.h" #include <iostream> int main() { const std::string token = "TOKEN"; TelegramBot bot(token, []() -> std::string { //get gpu temperature char buffer[128]; std::string result = ""; FILE* pipe = popen("nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader", "r"); if (!pipe) throw std::runtime_error("popen() failed!"); try { while (fgets(buffer, sizeof(buffer), pipe) != NULL) { result += buffer; } } catch (...) { pclose(pipe); throw; } pclose(pipe); return result; }); bot.start(); return 0; }
На этом все.
В этой статье я показал, как создать Telegram-бота на C++, который взаимодействует с Telegram API для отправки и получения сообщений. Если я помог хотя бы 1 человеку то потратил время на написании статьи не зря. Спасибо за внимание.
