C#和C++结构体Socket通信(二进制流与结构体)

27 篇文章 0 订阅
17 篇文章 0 订阅

本文转自:

http://blog.sina.com.cn/s/blog_455332580100j1xz.html

1、仿照C++结构体写出C#的结构体

    using System.Runtime.InteropServices;

    [Serializable] // 指示可序列化
    [StructLayout(LayoutKind.Sequential, Pack = 1)] // 按1字节对齐
    public struct Operator

    {
         public ushort id;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] // 声明一个字符数组,大小为11
        public char[] name;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
        public char[] pass;

         public Operator(string user, string pass) // 初始化
        {
            this.id = 10000;
            this.name = user.PadRight(11, '/0').ToCharArray();
            this.pass = pass.PadRight(9, '/0').ToCharArray();
        }
    }

2、注意C#与C++数据类型的对应关系

 

C++与C#的数据类型对应关系表
API数据类型类型描述C#类型API数据类型类型描述C#类型
WORD16位无符号整数ushortCHAR字符char
LONG32位无符号整数intDWORDLONG64位长整数long
DWORD32位无符号整数uintHDC设备描述表句柄int
HANDLE句柄,32位整数intHGDIOBJGDI对象句柄int
UINT32位无符号整数uintHINSTANCE实例句柄int
BOOL32位布尔型整数boolHWM窗口句柄int
LPSTR指向字符的32位指针stringHPARAM32位消息参数int
LPCSTR指向常字符的32位指针StringLPARAM32位消息参数int
BYTE字节byteWPARAM32位消息参数int

 

整个结构的字节数是22bytes。

对应的C++结构体是:

typedef struct
{
     WORD id;            
    CHAR name[11];
    CHAR password[9];
}Operator;

3、发送的时候先要把结构转换成字节数组

        using System.Runtime.InteropServices;     

         /// <summary>
        /// 将结构转换为字节数组
        /// </summary>
        /// <param name="obj">结构对象</param>
        /// <returns>字节数组</returns>
        public byte[] StructToBytes(object obj)
        {
            //得到结构体的大小
            int size = Marshal.SizeOf(obj);
            //创建byte数组
            byte[] bytes = new byte[size];
            //分配结构体大小的内存空间
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            //将结构体拷到分配好的内存空间
            Marshal.StructureToPtr(obj, structPtr, false);
            //从内存空间拷到byte数组
            Marshal.Copy(structPtr, bytes, 0, size);
            //释放内存空间
            Marshal.FreeHGlobal(structPtr);
            //返回byte数组
            return bytes;

       }

接收的时候需要把字节数组转换成结构

        /// <summary>
        /// byte数组转结构
        /// </summary>
        /// <param name="bytes">byte数组</param>
        /// <param name="type">结构类型</param>
        /// <returns>转换后的结构</returns>
        public object BytesToStruct(byte[] bytes, Type type)
        {
            //得到结构的大小
            int size = Marshal.SizeOf(type);
            Log(size.ToString(), 1);
            //byte数组长度小于结构的大小
            if (size > bytes.Length)
            {
                //返回空
                return null;
            }
            //分配结构大小的内存空间
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            //将byte数组拷到分配好的内存空间
            Marshal.Copy(bytes, 0, structPtr, size);
            //将内存空间转换为目标结构
            object obj = Marshal.PtrToStructure(structPtr, type);
            //释放内存空间
            Marshal.FreeHGlobal(structPtr);
            //返回结构
            return obj;
        }

4、实际操作

using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;

byte[] Message = StructToBytes(new Operator("user","pass")); // 将结构转换成字节数组

TcpClient socket = new TcpClient();

socket.Connect(ip,port);

NetworkStream ns = Socket.GetStream();

ns.Write(Message,0,Message.Length); // 发送

byte[] Recv = new byte[1024]; // 缓冲

int NumberOfRecv = 0;

IList<byte> newRecv = new List<byte>();
ns.ReadTimeout = 3000;
try
{
do
{
// 接收响应
NumberOfRecv = ns.Read(Recv, 0, Recv.Length);
for (int i = 0; i < NumberOfRecv; i++)
newRecv.Add(Recv[i]);
}
while (ns.DataAvailable);
byte[] resultRecv = new byte[newRecv.Count];
newRecv.CopyTo(resultRecv, 0);

Operator MyOper = new Operator();

MyOper = (Operator)BytesToStruct(resultRecv, MyOper.GetType()); // 将字节数组转换成结构

在这里取值的时候可能会出现只能取到一个字段,剩余的取不到的问题,怎么回事我也搞不懂,反正我的解决办法就是按照字节的顺序从resultRecv里分别取出对应的字段的字节数组,然后解码,例如:

Operator.name是11个字节,最后一位是0,Operator.id是2个字节,那么从第3位到第12位的字节就是Operator.name的内容,取出另存为一个数组MyOperName,Encoding.Default.GetString(MyOperName)就是MyOper.name的内容。

socket.Close();

ns.Close();

### 回答1: 对于您的问题,我可以回答。将C结构体转换为二进制,您可以使用以下方法: 1.使用memcpy()函数将结构体变量的内容复制到一个字符数组中。然后使用fwrite()函数将该字符数组写入文件或套接字。 例如: ```c struct MyStruct { int a; float b; char c; }; //将结构体变量转换为二进制 struct MyStruct s; char buffer[sizeof(struct MyStruct)]; memcpy(buffer, &s, sizeof(struct MyStruct)); //将二进制写入文件 FILE *fp; fp = fopen("output.bin", "wb"); fwrite(buffer, sizeof(struct MyStruct), 1, fp); fclose(fp); ``` 2.使用一个打包库,如Google的protobuf或Apache Thrift,可以将结构体序列化为二进制,并且可以跨语言进行交互。 例如,使用protobuf库: ```c //定义protobuf消息 message MyMessage { int32 a = 1; float b = 2; string c = 3; } //将结构体转换为protobuf消息 struct MyStruct s; MyMessage msg; msg.set_a(s.a); msg.set_b(s.b); msg.set_c(string(1, s.c)); //将protobuf消息序列化为二进制 string output; msg.SerializeToString(&output); ``` 希望这些信息可以帮助到您。 ### 回答2: 在C语言中,通过使用struct结构体可以定义一种数据结构,该结构体可以包含不同类型的成员变量。当需要将这个结构体转换成二进制时,可以使用以下步骤: 1. 创建一个struct结构体对象,并对其成员变量进行赋值。 2. 创建一个指向该结构体对象的指针。 3. 使用sizeof运算符来获取结构体对象的大小,这将用于后续的二进制缓冲区的分配。 4. 分配一个大小为结构体大小的二进制缓冲区,可以使用malloc函数动态分配内存。 5. 将struct结构体指针转换为一个指向无类型(void)的指针。 6. 使用memcpy函数将struct结构体指针所指的内存块中的数据拷贝到二进制缓冲区中。 7. 现在,二进制已经存储在缓冲区中,可以对其进行读写或者进行网络传输等操作。 8. 在结束使用后,记得使用free函数释放之前动态分配的内存空间,以避免内存泄露。 总结:通过以上步骤,我们可以将struct结构体转换成二进制。建立结构体对象,指向它的指针,用sizeof运算符获取大小,动态分配缓冲区,使用memcpy函数拷贝数据,把结构体转换为二进制。最后进行相应的操作后,使用free函数释放内存。 ### 回答3: 在C语言中,可以使用`struct`结构体来定义一组相关的变量,并将它们作为一个整体进行处理。而将结构体转换为二进制,在网络编程中是非常常见的操作。 要将`struct`结构体转换为二进制,可以使用`memcpy`函数来实现。首先,我们可以定义一个结构体类型,例如: ```c typedef struct { int id; char name[20]; float score; } Student; ``` 接下来,我们可以创建一个`Student`类型的结构体变量,并给其成员赋值。然后,可以通过`memcpy`函数将结构体变量的数据拷贝到一个字节数组中,即转换为二进制: ```c Student student; student.id = 1; strcpy(student.name, "Tom"); student.score = 90.5; char buffer[sizeof(Student)]; memcpy(buffer, &student, sizeof(Student)); ``` 上述代码中,`buffer`是一个与结构体大小相等的字节数组。`memcpy`函数将`student`变量的数据拷贝到`buffer`数组中。 如果需要将二进制转换回`struct`结构体,可以使用相反的步骤。先创建一个目标结构体类型的变量,再通过`memcpy`函数将二进制的数据拷贝到该变量中: ```c Student student2; memcpy(&student2, buffer, sizeof(Student)); printf("Student ID: %d\n", student2.id); printf("Student Name: %s\n", student2.name); printf("Student Score: %.1f\n", student2.score); ``` 通过上述代码,我们可以将二进制再转换回原来的结构体变量并打印出来。 总之,通过使用`memcpy`函数,我们可以在C语言中方便地将结构体转换为二进制,并在需要时将其转换回来。这在网络传输、文件IO等场景中都非常有用。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值