C#包发送到c ++ winsockets

时间:2014-04-19 06:56:41

标签: c# c++ sockets marshalling winsock

我只是想在我的两个应用程序之间来回发送数据包,但我的字符串在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,它是struct中的第一个值。一个人总是通过。我错过了什么?

3 个答案:

答案 0 :(得分:1)

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

您需要将数据序列化为内存流。为你的字符串使用适当的编码等类。然后在C ++应用程序中反序列化它。

尝试使用下面的c#应用程序,然后在c ++中执行反向操作,它将起作用。另一种方法是首先读取4个字节,以告诉字符串提前读取多少...读取字符串...继续下一个字符串,直到找到文件结束标记。< / p>

            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 :(得分:0)

你有几个问题:

  1. 在C#侧,编组大小定义为32字节而不是4 + 2 * 8 * 4 = 68字节。最好删除Size
  2. 中的StructureLayout字段
  3. 在C ++中,您定义了char而不是wchar_ t,在C#端有Unicode字符串
  4. 您定义了指针而不是数组,因此:
    • sizeof(Packet)是20。
    • memcpy在Packet struct之外复制
    • 您的代码尝试访问无效内存,因为它会将字符串值转换为指针。
  5. 在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];
        // ...
    };
    

答案 2 :(得分:0)

问题是你将字符串作为指针传递。指针仅在同一过程中有效。如果您的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 ++都必须是SAME大小。并且不要忘记在每个字符串的末尾添加空字符。