Asio TCP-клиент прерывается при асинхронности ⇐ C++
Asio TCP-клиент прерывается при асинхронности
В настоящее время я пытаюсь связаться с Unreal Engine 5 с существующим программным обеспечением, которое работает в нашей компании. Это программное обеспечение принимает TCP-соединения.
Поскольку это кажется стандартом де-факто для C++, я хотел использовать для этого asio (автономный, без повышения). Следуя некоторым онлайн-руководствам и публикациям, мне удалось создать работающий клиент, который подключается синхронно, а затем асинхронно ожидает сообщений. Это работает до тех пор, пока серверное приложение уже запущено, когда я запускаю клиент.
//IOSocket.h (исключая объявления функций) статический constexpr int BUFFER_SIZE = 4096; статический constexpr int MAX_CONNECTION_ATTEMPTS = 3; std::array _buffer; asio::io_context _context; asio::ip::tcp::endpoint _endpoint; asio::ip::tcp::socket _socket; std::queue _outMessageQueue; //IOSocket.cpp IOSocket::IOSocket(const std::string& имя хоста, const uint16_t& порт): _buffer(), _socket(_context) { asio::ip::адрес ip; if (имя хоста == "localhost" || имя хоста == "loopback") { ip = asio::ip::address_v4::loopback(); } еще { ip = asio::ip::адрес::from_string(имя хоста); } _endpoint = asio::ip::tcp::endpoint(ip, порт); asio::io_context::work Idle(_context); _contextThread = std::thread([this]() { _context.run(); }); Соединять(); } IOSocket::~IOSocket() { Отключить (ложь); _context.stop(); если (_contextThread.joinable()) { _contextThread.join(); } } недействительный IOSocket::Connect() { Отключить(); //открываем TCP-сокет ошибка asio::error_code; _socket.connect(_endpoint, ошибка); если (ошибка) { Отключить(); возвращаться; } for (; !_outMessageQueue.empty(); _outMessageQueue.pop()) { SendMessage(_outMessageQueue.front()); } //начинаем получать ПолучитьДанные(); } void IOSocket::Disconnect() { если (_socket.is_open()) { ошибка asio::error_code; _socket.shutdown(asio::socket_base::shutdown_both, ошибка); _socket.close(ошибка); } } void IOSocket::ReceiveData() { _socket.async_read_some(asio::buffer(_buffer), [&](asio::error_code error, std::size_t ReceviedBytes) { если (! ошибка) { const std::vector msgs = Utilities::String::Split(_buffer.data(), '*'); for (const std::string& msg : msgs) { //Сообщение обрабатывается владельцем IOSocket } ПолучитьДанные(); } }); } void IOSocket::SendMessage(const std::string& message) { если (_socket.is_open()) { запись (_socket, asio::buffer (сообщение)); } еще { _outMessageQueue.push(сообщение); } } Однако я хочу, чтобы клиент попытался подключиться вначале на некоторое время (3 попытки с десятисекундным интервалом), а когда клиент уже установил соединение, а сервер исчезнет, я бы хотел, чтобы клиент оставался на неопределенный срок. попробуйте переподключиться, пока сервер снова не вернется. Поэтому я изменил функции Connect и Disconnect для повторного подключения с помощью вспомогательной асинхронной функции:
//Дополнения IOSocket.h std::thread _contextThread; std::future _waitForReconnect; //IOSocket.cpp void IOSocket::Connect(int restAttempts) { Отключить (ложь); //открываем TCP-сокет ошибка asio::error_code; _socket.connect(_endpoint, ошибка); если (ошибка) { оставшиеся попытки--; если (оставшиеся попытки >= 0) { int currentAttempt = MAX_CONNECTION_ATTEMPTS - остающиеся попытки; Debug::LogWarning(std::format("Попытка подключения {0}/{1} не удалась: {2}", currentAttempt, MAX_CONNECTION_ATTEMPTS, error.message())); Disconnect (оставшиеся попытки > 0, остающиеся попытки); } еще { Debug::LogWarning(std::format("Ошибка подключения: {0}", error.message())); Отключить (истина); } возвращаться; } Debug::Log(std::format("Подключено к Solid в {0}:{1}", _endpoint.address().to_string(), _endpoint.port())); for (; !_outMessageQueue.empty(); _outMessageQueue.pop()) { SendMessage(_outMessageQueue.front()); } //начинаем получать ПолучитьДанные(); } void IOSocket::Disconnect(bool tryReconnect, int restAttempts) { если (_socket.is_open()) { ошибка asio::error_code; _socket.shutdown(asio::socket_base::shutdown_both, ошибка); _socket.close(ошибка); } если (попробуйReconnect) { _waitForReconnect = Utilities::Delay(10000, [this](int n) { Connect(n); }, restAttempts); } } //Утилиты.h шаблон статическая автоматическая задержка (uint32_t задержкиMilliсекунды, Fn&& fn, Args&&... аргументы) { return std::async(std::launch::async, [=](){ если (delayMilliсекунды > 0) { std::this_thread::sleep_for(std::chrono::milliсекунды(delayMilliсекунды)); } фн(аргументы...); }); } Это почти работает. Я получаю соединение и могу отправлять сообщения, но ничего не получаю. Если я отлаживаю и устанавливаю точку останова в любой отложенной функции, io_context «остановлен», а «outstanding_work» равен 0. Даже если я перезапущу его и дам ему новую «фальшивую» работу, я все равно не получу входящие процессы. Сообщения. Если я делаю первоначальную попытку подключения синхронно (и сервер работает), это по-прежнему создает работающее соединение, но повторное подключение - нет, а если я делаю начальную попытку асинхронно, оно показывает то же поведение, что и повторное подключение. Нет никакой разницы между вызовом его через мою функцию Delay, явным вызовом std::thread или ручным вызовом std::async.
Я новичок в asio и не писал код на C++ уже почти десять лет (обычно я использую C#), поэтому я уверен, что многое делаю неправильно, но я просто не могу понять что это такое.
В настоящее время я пытаюсь связаться с Unreal Engine 5 с существующим программным обеспечением, которое работает в нашей компании. Это программное обеспечение принимает TCP-соединения.
Поскольку это кажется стандартом де-факто для C++, я хотел использовать для этого asio (автономный, без повышения). Следуя некоторым онлайн-руководствам и публикациям, мне удалось создать работающий клиент, который подключается синхронно, а затем асинхронно ожидает сообщений. Это работает до тех пор, пока серверное приложение уже запущено, когда я запускаю клиент.
//IOSocket.h (исключая объявления функций) статический constexpr int BUFFER_SIZE = 4096; статический constexpr int MAX_CONNECTION_ATTEMPTS = 3; std::array _buffer; asio::io_context _context; asio::ip::tcp::endpoint _endpoint; asio::ip::tcp::socket _socket; std::queue _outMessageQueue; //IOSocket.cpp IOSocket::IOSocket(const std::string& имя хоста, const uint16_t& порт): _buffer(), _socket(_context) { asio::ip::адрес ip; if (имя хоста == "localhost" || имя хоста == "loopback") { ip = asio::ip::address_v4::loopback(); } еще { ip = asio::ip::адрес::from_string(имя хоста); } _endpoint = asio::ip::tcp::endpoint(ip, порт); asio::io_context::work Idle(_context); _contextThread = std::thread([this]() { _context.run(); }); Соединять(); } IOSocket::~IOSocket() { Отключить (ложь); _context.stop(); если (_contextThread.joinable()) { _contextThread.join(); } } недействительный IOSocket::Connect() { Отключить(); //открываем TCP-сокет ошибка asio::error_code; _socket.connect(_endpoint, ошибка); если (ошибка) { Отключить(); возвращаться; } for (; !_outMessageQueue.empty(); _outMessageQueue.pop()) { SendMessage(_outMessageQueue.front()); } //начинаем получать ПолучитьДанные(); } void IOSocket::Disconnect() { если (_socket.is_open()) { ошибка asio::error_code; _socket.shutdown(asio::socket_base::shutdown_both, ошибка); _socket.close(ошибка); } } void IOSocket::ReceiveData() { _socket.async_read_some(asio::buffer(_buffer), [&](asio::error_code error, std::size_t ReceviedBytes) { если (! ошибка) { const std::vector msgs = Utilities::String::Split(_buffer.data(), '*'); for (const std::string& msg : msgs) { //Сообщение обрабатывается владельцем IOSocket } ПолучитьДанные(); } }); } void IOSocket::SendMessage(const std::string& message) { если (_socket.is_open()) { запись (_socket, asio::buffer (сообщение)); } еще { _outMessageQueue.push(сообщение); } } Однако я хочу, чтобы клиент попытался подключиться вначале на некоторое время (3 попытки с десятисекундным интервалом), а когда клиент уже установил соединение, а сервер исчезнет, я бы хотел, чтобы клиент оставался на неопределенный срок. попробуйте переподключиться, пока сервер снова не вернется. Поэтому я изменил функции Connect и Disconnect для повторного подключения с помощью вспомогательной асинхронной функции:
//Дополнения IOSocket.h std::thread _contextThread; std::future _waitForReconnect; //IOSocket.cpp void IOSocket::Connect(int restAttempts) { Отключить (ложь); //открываем TCP-сокет ошибка asio::error_code; _socket.connect(_endpoint, ошибка); если (ошибка) { оставшиеся попытки--; если (оставшиеся попытки >= 0) { int currentAttempt = MAX_CONNECTION_ATTEMPTS - остающиеся попытки; Debug::LogWarning(std::format("Попытка подключения {0}/{1} не удалась: {2}", currentAttempt, MAX_CONNECTION_ATTEMPTS, error.message())); Disconnect (оставшиеся попытки > 0, остающиеся попытки); } еще { Debug::LogWarning(std::format("Ошибка подключения: {0}", error.message())); Отключить (истина); } возвращаться; } Debug::Log(std::format("Подключено к Solid в {0}:{1}", _endpoint.address().to_string(), _endpoint.port())); for (; !_outMessageQueue.empty(); _outMessageQueue.pop()) { SendMessage(_outMessageQueue.front()); } //начинаем получать ПолучитьДанные(); } void IOSocket::Disconnect(bool tryReconnect, int restAttempts) { если (_socket.is_open()) { ошибка asio::error_code; _socket.shutdown(asio::socket_base::shutdown_both, ошибка); _socket.close(ошибка); } если (попробуйReconnect) { _waitForReconnect = Utilities::Delay(10000, [this](int n) { Connect(n); }, restAttempts); } } //Утилиты.h шаблон статическая автоматическая задержка (uint32_t задержкиMilliсекунды, Fn&& fn, Args&&... аргументы) { return std::async(std::launch::async, [=](){ если (delayMilliсекунды > 0) { std::this_thread::sleep_for(std::chrono::milliсекунды(delayMilliсекунды)); } фн(аргументы...); }); } Это почти работает. Я получаю соединение и могу отправлять сообщения, но ничего не получаю. Если я отлаживаю и устанавливаю точку останова в любой отложенной функции, io_context «остановлен», а «outstanding_work» равен 0. Даже если я перезапущу его и дам ему новую «фальшивую» работу, я все равно не получу входящие процессы. Сообщения. Если я делаю первоначальную попытку подключения синхронно (и сервер работает), это по-прежнему создает работающее соединение, но повторное подключение - нет, а если я делаю начальную попытку асинхронно, оно показывает то же поведение, что и повторное подключение. Нет никакой разницы между вызовом его через мою функцию Delay, явным вызовом std::thread или ручным вызовом std::async.
Я новичок в asio и не писал код на C++ уже почти десять лет (обычно я использую C#), поэтому я уверен, что многое делаю неправильно, но я просто не могу понять что это такое.
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
TCP-клиент Spring Integration не может получать сообщения от внешнего TCP-сервера
Anonymous » » в форуме JAVA - 0 Ответы
- 38 Просмотры
-
Последнее сообщение Anonymous
-