// NetClient.h #pragma once #include #include #using #using using namespace System; using namespace System::Net; using namespace System::Net::Sockets; using namespace System::Runtime::InteropServices; namespace DroneSimulator { public ref class NetClient { public: // Вложенный класс для данных подключения ref class ConnectData { public: property bool Connect; property Socket^ Server; }; // Вложенный класс для данных приема ref class ReceiveData { public: property array^ Buffer; property int Size; property Socket^ Server; }; // Состояния клиента enum class ClientState { Error, Connected, Stop }; // Делегат для callback-функций delegate void ClientCallback(Object^ o); NetClient() { Connected = false; ServerSocket = nullptr; DataServer = gcnew ServerData(); } ~NetClient() { // Вызываем Close() для корректного закрытия соединения Close(); // Дополнительная очистка ресурсов if (DataServer != nullptr) { // Очищаем буфер данных DataServer->buffer = nullptr; DataServer = nullptr; } // Обнуляем callback-делегаты ConnectionCallback = nullptr; ReceiveCallback = nullptr; } ClientState Connect(String^ addr, int port, ClientCallback^ connectionCallback, ClientCallback^ receiveCallback) { if (Connected) { Disconnect(); return ClientState::Stop; } ConnectionCallback = connectionCallback; ReceiveCallback = receiveCallback; try { IPEndPoint^ ep = gcnew IPEndPoint(IPAddress::Parse(addr), port); ServerSocket = gcnew Socket(AddressFamily::InterNetwork, SocketType::Stream, ProtocolType::Tcp); ServerSocket->Connect(ep); Connected = true; // Уведомление о подключении ConnectData^ connectData = gcnew ConnectData(); connectData->Connect = true; connectData->Server = ServerSocket; ConnectionCallback(connectData); // Начало приема данных ReceiveData^ receiveData = gcnew ReceiveData(); receiveData->Buffer = DataServer->buffer; receiveData->Size = ServerData::size; receiveData->Server = ServerSocket; ServerSocket->BeginReceive(DataServer->buffer, 0, ServerData::size, SocketFlags::None, gcnew AsyncCallback(this, &NetClient::ReadCallback), receiveData); return ClientState::Connected; } catch (Exception^) { if (ServerSocket != nullptr) { ServerSocket->Close(); } return ClientState::Error; } } void Close() { Disconnect(); } private: ref class ServerData { public: static const int size = 1024; array^ buffer = gcnew array(size); }; bool Connected; Socket^ ServerSocket; ServerData^ DataServer; ClientCallback^ ConnectionCallback; ClientCallback^ ReceiveCallback; void Disconnect() { if (ServerSocket != nullptr) { try { ServerSocket->Shutdown(SocketShutdown::Both); } catch (...) {} ServerSocket->Close(); ServerSocket = nullptr; } Connected = false; } void ReadCallback(IAsyncResult^ ar) { try { // Проверка на null входного параметра if (ar == nullptr) return; // Безопасное приведение типа ReceiveData^ cd = dynamic_cast(ar->AsyncState); if (cd == nullptr || ServerSocket == nullptr || !ServerSocket->Connected) { Disconnect(); return; } int bytes = 0; try { bytes = ServerSocket->EndReceive(ar); } catch (ObjectDisposedException^) { // Сокет был закрыт Disconnect(); return; } catch (SocketException^ ex) { // Логирование ошибки сокета System::Diagnostics::Debug::WriteLine( "Socket receive error: " + ex->Message); Disconnect(); return; } catch (...) { Disconnect(); return; } // Проверка на разрыв соединения if (bytes == 0) { Disconnect(); if (ConnectionCallback != nullptr) { ConnectData^ disconnectData = gcnew ConnectData(); disconnectData->Connect = false; disconnectData->Server = nullptr; ConnectionCallback(disconnectData); } return; } // Вызов callback получения данных if (ReceiveCallback != nullptr && cd->Buffer != nullptr) { try { ReceiveCallback(cd); } catch (Exception^ ex) { System::Diagnostics::Debug::WriteLine( "ReceiveCallback error: " + ex->Message); } } // Продолжаем прием данных if (ServerSocket != nullptr && ServerSocket->Connected) { try { IAsyncResult^ result = ServerSocket->BeginReceive( cd->Buffer, 0, ServerData::size, SocketFlags::None, gcnew AsyncCallback(this, &NetClient::ReadCallback), cd); // Проверка на ошибку асинхронной операции if (result == nullptr) { Disconnect(); } } catch (ObjectDisposedException^) { Disconnect(); } catch (SocketException^ ex) { System::Diagnostics::Debug::WriteLine( "BeginReceive error: " + ex->Message); Disconnect(); } catch (...) { Disconnect(); } } } catch (Exception^ ex) { System::Diagnostics::Debug::WriteLine( "ReadCallback general error: " + ex->Message); Disconnect(); } } }; }