如何在 C++ Builder 中使用 Indy TCP Client 写入原始二进制数据

How to write raw binary data using Indy TCP Client in C++ Builder

使用 Embarcadero C++ Builder 10.3。

我有一个 DynamicArray<uint8_t> myData 对象。我想 send/write 它的原始二进制内容(字节)到使用 TIdTcpClient 组件的服务器。我打算这样做:

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

其中 rawData 应为 TIdBytesTIdStream

类型

所以基本上,它归结为以下内容:如何将 myData 对象转换为 TIdBytesTIdStreamrawData 类型?

首先,TIdStream 已经很长时间没有成为 Indy 的一部分了,这让我想知道您是否使用的是非常旧的 Indy 版本,而不是 C++ 附带的版本生成器 10.3。 Indy 已经支持 RTL 的标准 TStream class 很长时间了。

话虽这么说...

TIdBytesSystem::DynamicArray<System::Byte> 的别名,其中 System::Byteunsigned char 的别名,大小和 sign-ness 与 uint8_t(取决于编译器,uint8_t 甚至可能只是 unsigned char 的别名)。

因此,最简单的解决方案,无需 单独复制您的数据,就是简单地type-cast 它,例如:

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

这在技术上是 未定义的行为,因为 DynamicArray<uint8_t>DynamicArray<Byte> 是不相关的类型(除非 uint8_tByteunsigned char) 的两个别名),但它适用于您的情况,因为它是两个数组背后的相同底层代码,并且 uint8_tByte 具有相同的底层内存布局。

或者,下一个最简单的解决方案,没有复制数据或调用未定义的行为,是在IdGlobal.hpp中使用Indy的TIdReadOnlyMemoryBufferStream class ,例如:

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中,eg:

{
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);
}