Как записать необработанные двоичные данные с помощью Indy TCP Client в C++ Builder

Использование Embarcadero C++ Builder 10.3.

У меня есть объект DynamicArray<uint8_t> myData. Я хочу отправить/записать необработанный двоичный контент (байты) на сервер с помощью компонента TIdTcpClient. Я поступаю так:

TIdTcpClient tcpClient1;
// Bla Bla Bla
tcpClient1->IOHandler->Write(rawData);

Где rawData должен быть типа TIdBytes или TIdStream

Итак, в основном все сводится к следующему: как преобразовать myData объект в rawData тип TIdBytes или TIdStream?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Во-первых, TIdStream не был частью Indy ОЧЕНЬ ОЧЕНЬ ДОЛГО, что заставляет меня задуматься, используете ли вы очень старую версию Indy, а не ту, которая поставляется с C++Builder 10.3. Indy уже очень давно поддерживает стандартный класс RTL TStream.

Что, как говорится...

TIdBytes — это псевдоним для System::DynamicArray<System::Byte>, где System::Byte — это псевдоним для unsigned char, который имеет тот же размер и знак, что и uint8_t (в зависимости от компилятора, uint8_t может даже быть просто псевдонимом для unsigned char).

Таким образом, самое простое решение, когда без необходимо сделать отдельную копию ваших данных, — это просто привести ее к типу, например:

tcpClient1->IOHandler->Write(reinterpret_cast<TIdBytes&>(myData));

Технически это неопределенное поведение, поскольку DynamicArray<uint8_t> и DynamicArray<Byte> являются несвязанными типами (если только uint8_t и Byte не являются псевдонимами для unsigned char), но это будет работать в вашем случае, поскольку это один и тот же базовый код для обоих массивов, а uint8_t и Byte имеют одинаковую базовую основу макет памяти.

В качестве альтернативы, следующее простейшее решение, копирование данных без или вызов неопределенного поведения, заключается в использовании класса Indy TIdReadOnlyMemoryBufferStream в IdGlobal.hpp, например:

TIdReadOnlyMemoryBufferStream *ms = new TIdReadOnlyMemoryBufferStream(&myData[0], myData.Length);
try {
    tcpClient1->IOHandler->Write(ms);
}
__finally {
    delete ms;
}

Или:

{
auto ms = std::make_unique<TIdReadOnlyMemoryBufferStream>(&myData[0], myData.Length);
tcpClient1->IOHandler->Write(ms.get());
}

В противном случае окончательным решением будет просто скопировать данные в TIdBytes, например:

{
TIdBytes bytes;
bytes.Length = myData.Length;

memcpy(&bytes[0], &myData[0], myData.Length);
or:
std::copy(myData.begin(), myData.end(), bytes.begin());

tcpClient1->IOHandler->Write(bytes);
}

Согласно документации Indy, поставляемой с C++ Builder 10.3, одной из перегрузок метода IOHandler в Write является TIdIOHandler.Write (TIdStream, Int64, Boolean). Согласно stdint.h, uint8_t определяется не как typedef unsigned char, а как typedef unsigned __int8, где __int8 — расширенный интегральный тип фиксированной длины. При этом я не думаю, что поведение undefined будет проблемой. Еще лучше заменить мои uint8_ts на System::Byte.

Makaveli84 09.05.2022 20:18

Документация Indy очень старая, она давно не обновлялась. В этом случае TIdIOHandler.Write (TIdStream, Int64, Boolean) теперь TIdIOHandler.Write (TStream, Int64, Boolean)

Remy Lebeau 09.05.2022 21:12

Другие вопросы по теме