发送到C++winsockets的C#数据包

C# packet sent to c++ winsockets

本文关键字:数据包 C++winsockets      更新时间:2023-10-16

我只是想在我的两个应用程序之间来回发送数据包,但我的字符串在c++中无法通过。这是我在c#中所做的

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Size=32)]
public struct Packet
{
    public uint packet_type;
    [MarshalAs(UnmanagedType.LPWStr, SizeConst = 8)]
    public string file_name;
    [MarshalAs(UnmanagedType.LPWStr, SizeConst = 8)]
    public string template_name;
    [MarshalAs(UnmanagedType.LPWStr, SizeConst = 8)]
    public string file_name_list;
    [MarshalAs(UnmanagedType.LPWStr, SizeConst = 8)]
    public string file_buffer;
}
var data = new Packet
{
    packet_type = (uint)action,
    file_name = fileName + Char.MinValue,
    file_name_list = "" + Char.MinValue,
    template_name = "" + Char.MinValue
};
byte[] buffer = new byte[Marshal.SizeOf(typeof(Packet))];
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
Marshal.StructureToPtr(data, handle.AddrOfPinnedObject(), false);
handle.Free();
var bytesSent = _client.Client.Send(buffer);
byte[] buffer = new byte[Marshal.SizeOf(typeof(Packet))];
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
Marshal.StructureToPtr(data, handle.AddrOfPinnedObject(), false);
handle.Free();
var bytesSent = _client.Client.Send(buffer);

这是我在c++中得到的

struct Packet {
unsigned int packet_type;
char* file_name;
char* template_name;
char* file_name_list;
char* file_data;
void serialize(char * data) {
    memcpy(data, this, sizeof(Packet));
}
void deserialize(char * data) {
    memcpy(this, data, sizeof(Packet));
}
};
char network_data[MAX_PACKET_SIZE];
recv(curSocket, buffer, MAX_PACKET_SIZE, 0);

唯一有效的值是packet_type,它是结构中的第一个值。那个总是挺过来的。我错过了什么?

尽管我从未尝试过这种方法,但我认为您不能简单地使用winsock在两个不同的应用程序之间共享数据,然后只传递指针。内存在两者之间受到保护。

您需要将数据序列化为内存流。将适当的类与Encoding等一起用于字符串。然后在C++应用程序中对其进行反序列化。

为你的c#应用程序尝试下面这样的方法,然后在你的c++中做相反的操作,它会起作用的。另一种方法是首先读取4个字节,告诉字符串要提前读取多少。。。。读取字符串。。。继续下一个,直到找到文件结束标记。

            string myString = "abc";
        byte[] buffer = System.Text.Encoding.UTF8.GetBytes(myString);

        using (MemoryStream ms = new MemoryStream())
        {
            ms.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
            ms.Write(buffer, 0, buffer.Length);
            //... rest of code...
        }

您有几个问题:

  1. 在C#端,封送大小定义为32字节,而不是4+2*8*4=68字节。最好删除StructureLayout中的Size字段
  2. 在C++中,您定义了char而不是wchar_t,在C#端有Unicode字符串
  3. 您定义了指针而不是数组,因此:
    • sizeof(Packet)为20
    • 数据包结构外部的memcpy副本
    • 您的代码试图访问无效内存,因为它将字符串值转换为指针

在C++中,数据包应定义如下:

struct Packet {
    unsigned int packet_type;
    wchar_t file_name[8];
    wchar_t template_name[8];
    wchar_t file_name_list[8];
    wchar_t file_data[8];
    // ...
};

问题是将字符串作为指针传递。指针仅在同一进程中有效。如果您的C#是2.0或更高版本,请将您的结构更改为:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct Packet
{
    public uint packet_type;
    public fixed char file_name[??];
    public fixed char template_name[??];
    public fixed char file_name_list[??];
    public fixed char file_buffer[??];
}
#pragma pack(push, 1)
struct Packet {
    unsigned int packet_type;
    wchar_t file_name[??];
    wchar_t template_name[??];
    wchar_t file_name_list[??];
    wchar_t file_data[??];
    void serialize(char * data) {
        memcpy(data, this, sizeof(Packet));
    }
    void deserialize(char * data) {
        memcpy(this, data, sizeof(Packet));
    }
};
#pragma pack(pop)

??替换为所需的大小,C#和C++的大小必须相同。不要忘记在每个字符串的末尾添加null字符。