2025-04-04 11:49:03 +03:00

256 lines
8.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// NetClient.h
#pragma once
#include <Windows.h>
#include <vcclr.h>
#using <System.dll>
#using <System.Net.dll>
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<Byte>^ 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<Byte>^ buffer = gcnew array<Byte>(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<ReceiveData^>(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();
}
}
};
}