0

我最近继承了一个混合 C++ 和 C++/CLI (.NET) 的程序。它通过网络连接到其他组件,并连接到某些特殊硬件的驱动程序 DLL。但是,我试图找出通过网络发送数据的最佳方式,因为使用的方式似乎不是最佳的。

数据存储在 C++ 定义的结构中,例如:

    struct myCppStructure {
        unsigned int field1;
        unsigned int field2;
        unsigned int dataArray[512];
    };

从 C++/CLI 访问结构本身时,程序运行良好。问题是要通过网络发送它,当前代码会执行以下操作:

    struct myCppStructure* data;
    IntPtr dataPtr(data);
    // myNetworkSocket is a NetworkStream cast as a System::IO::Stream^
    System::IO::BinaryWriter^ myBinWriter = gcnew BinaryWriter(myNetworkSocket);
    __int64 length = sizeof(struct myCppStructure) / sizeof(__int64);
    unsigned __int64* ptr = static_cast<__int64*>(dataPtr.toPointer());
    for (unsigned int i = 0; i < (length / sizeof(unsigned __int64)); i++)
        myBinWriter->Write((*ptr)++);

在普通的 C++ 中,它通常是这样的调用:

    myBinWriter->Write(ptr,length);

但我在 C++/CLI 中找不到任何等价的东西。System::IO::BinaryWriter 只有基本类型和其中一些的一些 array<>^ 版本。没有比这更有效的了吗?

PS 这些记录每秒生成很多次;所以做额外的复制(例如编组)是不可能的。

注意:最初的问题是关于 C# 的。我没有意识到我所认为的 C# 实际上是 .NET 下的“托管 C++”(又名 C++/CLI)。以上内容已经过编辑,以将“C#”引用替换为“C++/CLI”引用——我将其用于任何版本的托管 C++,尽管我特别使用的是 .NET 3.5。

4

3 回答 3

1

您要做的是找出 C++ 结构是如何打包的,并使用正确的StructLayout属性定义一个结构。

要定义固定长度的 int[],您可以在其中定义一个固定大小的缓冲区。请注意,要使用它,您必须将您的项目标记为 /unsafe。

现在您已准备好使用两个步骤将该结构转换为 byte[]

  1. 使用GCHandle.Alloc将结构数组固定在内存中- 这很快,不应该成为性能瓶颈。
  2. 现在使用带有源 IntPtr = handle .AddrOfPinnedObject的Marshal.Copy(别担心,这和 memcpy 一样快)。

现在处理 GCHandle,您就可以使用Serg Rogovtsev 提到的“Write”重载来写入字节了。

希望这可以帮助!

于 2012-07-31T21:00:01.513 回答
1

您的结构由“基本类型”和“它们的数组”组成。为什么你不能使用顺序写它们BinaryWriter?就像是

binWriter.Write(data.field1);
binWriter.Write(data.field2);
for(var i = 0; i < 512; i++)
    binWriter.Write(data.dataArray[i]);
于 2012-07-31T21:04:02.020 回答
0

在 C# 中,您可以执行以下操作。首先定义结构。

[StructLayout ( LayoutKind.Sequential )]
internal unsafe struct hisCppStruct
{
    public uint field1;
    public uint field2;
    public fixed uint dataArray [ 512 ];
}

然后使用二进制编写器编写它,如下所示。

hisCppStruct @struct = new hisCppStruct ();
@struct.field1 = 1;
@struct.field2 = 2;
@struct.dataArray [ 0 ] = 3;
@struct.dataArray [ 511 ] = 4;

using ( BinaryWriter bw = new BinaryWriter ( File.OpenWrite ( @"C:\temp\test.bin") ) )
{
    int structSize = Marshal.SizeOf ( @struct );
    int limit = structSize / sizeof ( uint );

    uint* uintPtr = (uint*) &@struct;

    for ( int i = 0 ; i < limit ; i++ )
        bw.Write ( uintPtr [ i ] );
}

我很确定你可以在托管 C++ 中做同样的事情。

于 2012-08-01T06:42:24.480 回答